1 Functions

2 Data

acc_pri = subset(hmsc_acc_pri_cancer,subset = patient.ident != "HMSC")
Warning: Keys should be one or more alphanumeric characters followed by an underscore, setting key from pca_integrated_ to pcaintegrated_
Warning: Keys should be one or more alphanumeric characters followed by an underscore, setting key from umap_integrated_ to umapintegrated_

3 HMSC vs ACC

3.1 UMAP

DimPlot(hmsc_acc_pri_cancer,group.by = "patient.ident",label = T)

FeaturePlot(object = hmsc_acc_pri_cancer,features = c("MYB"),pt.size = 1)

FeaturePlot(object = hmsc_acc_pri_cancer,features = c("kaye_acc_score"),pt.size = 1)

pdf("./Figures/kaye_acc_score_AllCancerCells.pdf")
FeaturePlot(object = all_acc_cancer_cells,features = c("kaye_acc_score"),pt.size = 1)
dev.off()
null device 
          1 

3.2 enrichment analysis

3.3 Cell cycle score

DefaultAssay(hmsc_cancer_cells) = "RNA"
hallmark_name = "GO_MITOTIC_CELL_CYCLE"
acc_pri = ScaleData(object = acc_pri,features = VariableFeatures(acc_pri,assay = "RNA"))
Centering and scaling data matrix

  |                                                                                                                
  |                                                                                                          |   0%
  |                                                                                                                
  |=======                                                                                                   |   7%
  |                                                                                                                
  |==============                                                                                            |  13%
  |                                                                                                                
  |=====================                                                                                     |  20%
  |                                                                                                                
  |============================                                                                              |  27%
  |                                                                                                                
  |===================================                                                                       |  33%
  |                                                                                                                
  |==========================================                                                                |  40%
  |                                                                                                                
  |=================================================                                                         |  47%
  |                                                                                                                
  |=========================================================                                                 |  53%
  |                                                                                                                
  |================================================================                                          |  60%
  |                                                                                                                
  |=======================================================================                                   |  67%
  |                                                                                                                
  |==============================================================================                            |  73%
  |                                                                                                                
  |=====================================================================================                     |  80%
  |                                                                                                                
  |============================================================================================              |  87%
  |                                                                                                                
  |===================================================================================================       |  93%
  |                                                                                                                
  |==========================================================================================================| 100%
geneIds= genesets_h[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(acc_pri,assay = "RNA")) 
score <- apply(acc_pri@assays$RNA@scale.data[geneIds,],2,mean)
acc_pri=AddMetaData(acc_pri,score,hallmark_name)

hmsc_cancer_cells = FindVariableFeatures(object = hmsc_cancer_cells,nfeatures = 15000)
Calculating gene variances
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Calculating feature variances of standardized and clipped values
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
hmsc_cancer_cells = ScaleData(object = hmsc_cancer_cells,features = VariableFeatures(hmsc_cancer_cells))
Centering and scaling data matrix

  |                                                                                                                
  |                                                                                                          |   0%
  |                                                                                                                
  |=======                                                                                                   |   7%
  |                                                                                                                
  |==============                                                                                            |  13%
  |                                                                                                                
  |=====================                                                                                     |  20%
  |                                                                                                                
  |============================                                                                              |  27%
  |                                                                                                                
  |===================================                                                                       |  33%
  |                                                                                                                
  |==========================================                                                                |  40%
  |                                                                                                                
  |=================================================                                                         |  47%
  |                                                                                                                
  |=========================================================                                                 |  53%
  |                                                                                                                
  |================================================================                                          |  60%
  |                                                                                                                
  |=======================================================================                                   |  67%
  |                                                                                                                
  |==============================================================================                            |  73%
  |                                                                                                                
  |=====================================================================================                     |  80%
  |                                                                                                                
  |============================================================================================              |  87%
  |                                                                                                                
  |===================================================================================================       |  93%
  |                                                                                                                
  |==========================================================================================================| 100%
geneIds= genesets_h[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(hmsc_cancer_cells)) 
score <- apply(hmsc_cancer_cells@assays$RNA@scale.data[geneIds,],2,mean)
hmsc_cancer_cells=AddMetaData(hmsc_cancer_cells,score,hallmark_name)
acc_cc_scores = FetchData(object = acc_pri,vars = "GO_MITOTIC_CELL_CYCLE")
hmsc_cc_scores = FetchData(object = hmsc_cancer_cells,vars = "GO_MITOTIC_CELL_CYCLE")

distributions_plt = ggplot() +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "ACC"), alpha = .2, data = acc_cc_scores) +
  geom_density(aes(GO_MITOTIC_CELL_CYCLE, fill = "HMSC"), alpha = .2, data = hmsc_cc_scores) +
  scale_fill_manual(name = "Dataset", values = c(ACC = "red", HMSC = "green"))+ geom_vline(aes(xintercept=0.3),
            color="blue", linetype="dashed", size=1) +ggtitle("'GO_MITOTIC_CELL_CYCLE'  score distribution")

print_tab(plt = distributions_plt,title = "score distribution",subtitle_num = 3)

score distribution

NA

hmsc_cc_cells = (sum(hmsc_cancer_cells@meta.data[[hallmark_name]]> 0.3) /ncol(hmsc_cancer_cells)) %>% round(digits = 3)*100
acc_cc_cells = (sum(acc_pri@meta.data[[hallmark_name]]> 0.3)/ncol(acc_pri)) %>% round(digits = 3)*100
df = data.frame(Dataset = c("HMSC","ACC"), cycling_cells_percentage = c(hmsc_cc_cells,acc_cc_cells))
cycling_cells_plt = ggplot(data=df, aes(x=Dataset, y=cycling_cells_percentage)) +
  geom_text(aes(label=cycling_cells_percentage), vjust=0, color="black", size=3.5)+
  geom_bar(stat="identity")+ylab(" % cycling cells")+
  geom_bar(stat="identity", fill="steelblue")+
  theme_minimal() + ggtitle("Cycling cells count")

print_tab(plt = cycling_cells_plt,title = "# cycling cells",subtitle_num = 3)

# cycling cells

NA

pdf(file = "./Figures/CC_distributions.pdf")
distributions_plt
dev.off()
null device 
          1 
pdf(file = "./Figures/cycling_cells.pdf")
cycling_cells_plt
dev.off()
null device 
          1 
print_tab(plt = 
            FeaturePlot(hmsc_acc_pri_cancer,features = c("MKI67","CDK1","MCM2","CDC20"))
          ,title = "CC genes",subtitle_num = 3)

CC genes

NA

3.4 Cycling cells filtering

#add score to all acc cancer cells
# geneIds= genesets[[hallmark_name]]@geneIds %>% intersect(VariableFeatures(all_acc_cancer_cells,assay = "integrated")) 
# score <- apply(all_acc_cancer_cells@assays$integrated@scale.data[geneIds,],2,mean)

#add score to all acc cancer cells
cc_all = c(acc_pri$GO_MITOTIC_CELL_CYCLE, hmsc_cancer_cells$GO_MITOTIC_CELL_CYCLE) %>% as.data.frame()
hmsc_acc_pri_cancer=AddMetaData(hmsc_acc_pri_cancer,cc_all,hallmark_name)

#filter:
all_acc_cancer_cells_ccFiltered=hmsc_acc_pri_cancer[,hmsc_acc_pri_cancer@meta.data[[hallmark_name]]< 0.3]
Warning: Keys should be one or more alphanumeric characters followed by an underscore, setting key from pca_integrated_ to pcaintegrated_
Warning: Keys should be one or more alphanumeric characters followed by an underscore, setting key from umap_integrated_ to umapintegrated_
min_threshold = min(hmsc_acc_pri_cancer$GO_MITOTIC_CELL_CYCLE)
max_threshold = max(hmsc_acc_pri_cancer$GO_MITOTIC_CELL_CYCLE)
library(viridis)

print_tab(plt = FeaturePlot(object = hmsc_acc_pri_cancer,features = hallmark_name) + ggtitle("Before cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "Before CC filtering",subtitle_num = 3)

Before CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

print_tab(plt = 
            FeaturePlot(object = all_acc_cancer_cells_ccFiltered,features = hallmark_name) + ggtitle("After cc filtering") &
            scale_color_gradientn(colours = plasma(n = 10, direction = -1), limits = c(min_threshold, max_threshold))
          ,title = "After CC filtering" ,subtitle_num = 3)

After CC filtering

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

3.5 DEG

all_acc_cancer_cells_ccFiltered = SetIdent(all_acc_cancer_cells_ccFiltered, value ="patient.ident")
acc_deg <-
  FindMarkers(
    all_acc_cancer_cells_ccFiltered,
    ident.1 = "HMSC",
    features = VariableFeatures(all_acc_cancer_cells_ccFiltered),
    densify = T,
    verbose = T,
    slot = "data",
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1,base = 2)) # change func to calculate logFC in log space data (default to exponent data)
    },
    assay = "RNA"
  )
library(hypeR)
genesets <- msigdb_download("Homo sapiens",category="H") %>% append( msigdb_download("Homo sapiens",category="C2",subcategory = "CP:KEGG"))
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = geneIds(genesets_h),up_only = F)

plt = hyp_dots(hyp_obj,merge = F)
plt1 = plt$up+ aes(size=nes)+ggtitle("up in HMSC")
plt2 = plt$dn+ aes(size=abs(nes))+ggtitle("up in ACC")
plt1+plt2

pdf(file = "./Figures/ACC_vs_HMSC_GSEA.pdf",width = 13,height = 6)
plt3
dev.off()
null device 
          1 
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)

pdf("./Figures/volcano_plot_ACC_VS_HMSC.pdf")
volcano_plot(de_genes = acc_deg,fdr_cutoff = 0.05,fc_cutoff = 2, ident1 = "HMSC",ident2 = "ACC",top_genes_text = 4)
dev.off()
null device 
          1 
pdf("./Figures/Enrichment_analysis_ACC_VS_HMSC.pdf")
enrichment_analysis(acc_deg,background = VariableFeatures(all_acc_cancer_cells_ccFiltered),fdr_Cutoff = 0.01,ident.1 =
                                      "HMSC",ident.2 = "ACC",show_by = 1)
dev.off()
null device 
          1 
top_hmsc_genes = acc_deg %>% dplyr::filter(avg_log2FC > 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
top_acc_genes = acc_deg %>% dplyr::filter(avg_log2FC < 0) %>%  slice_min(n = 10,order_by = p_val_adj) %>% rownames()
all_top_deg = c(top_hmsc_genes,top_acc_genes)

all_acc_cancer_cells_ccFiltered$cancer_type = all_acc_cancer_cells_ccFiltered$patient.ident %>% gsub(pattern = "ACC.*",replacement = "ACC")
cancer_type = FetchData(object = all_acc_cancer_cells_ccFiltered, vars = "cancer_type")
# col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
column_ha = HeatmapAnnotation(df = cancer_type)

data = FetchData(object = all_acc_cancer_cells_ccFiltered,vars = all_top_deg,slot = "scale.data") %>% t()

print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, ,name = "Z-score expression",cluster_columns = F,top_annotation = column_ha))

NA
NA

3.6 CNV plot

# create expression matrix of acc + normal cells + HMSC seurat integrated
# acc_all_cells_noAcc1 = subset(acc_all_cells, subset = patient.ident != "ACC1")
# acc_expr = acc_all_cells_noAcc1@assays$RNA@data %>% as.data.frame()
# hmsc_expr  = acc.combined@assays$integrated@data %>% as.data.frame()
# acc_expr = acc_expr [ rownames(hmsc_expr),]
# all_expr = cbind(acc_expr,hmsc_expr)
# 
# # create annotation 
# acc_annotation_integrated  = as.data.frame(acc_all_cells@meta.data[,"cell.type",drop = F])
# acc_annotation_integrated = acc_annotation_integrated[colnames(all_expr),,drop = F]
# acc_annotation_integrated = acc_annotation_integrated %>% rownames_to_column("orig.ident") 

# #write expression and annotation
# write.table(acc_annotation_integrated, "./Data/inferCNV/acc_annotation_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = FALSE, col.names = F)
# 
# 
# write.table(all_expr, "./Data/inferCNV/all.4icnv_integrated.txt", append = FALSE, 
#             sep = "\t", dec = ".",row.names = T, col.names = T)
trace(infercnv::run,edit = T) # to skip normalization, change to skip_past = 4 (https://github.com/broadinstitute/infercnv/issues/346)
Tracing function "run" in package "infercnv"
[1] "run"

infercnv_obj = CreateInfercnvObject(raw_counts_matrix="./Data/inferCNV/all.4icnv_integrated.txt", 
                                    annotations_file="./Data/inferCNV/acc_annotation_integrated.txt",
                                    delim="\t",gene_order_file="./Data/inferCNV/gencode_v19_gene_pos.txt"
                                    ,ref_group_names=c("CAF", "Endothelial", "WBC")) #groups of normal cells

infercnv_obj_default = infercnv::run(infercnv_obj, cutoff=1, out_dir='./Data/inferCNV/infercnv_intergrated_output',
                                     cluster_by_groups=T, plot_steps=FALSE,
                                     denoise=TRUE, HMM=FALSE, no_prelim_plot=TRUE,
                                     png_res=300)
untrace(infercnv::run)
trace(infercnv:::get_group_color_palette ,edit = T) # change "Set3" to "Set1" for more distinguishable colors
plot_cnv(infercnv_obj_default, output_format = "png",  write_expr_matrix = FALSE,out_dir = "./Data/inferCNV/infercnv_intergrated_output",png_res    =800,obs_title = "Malignant cells",ref_title = "Normal cells",contig_cex = 2, title = "Copy number variation")
untrace(infercnv:::get_group_color_palette)
print_tab(plt = knitr::include_graphics("./Data/inferCNV/infercnv_intergrated_output/infercnv.png")
          ,title = "CNV plot",subtitle_num = 3)

CNV plot

NA

library(limma)
smoothed=apply(infercnv_obj_default@expr.data,2,tricubeMovingAverage, span=0.01)
cnsig=sqrt(apply((smoothed-1)^2,2,mean))

acc_all_cells <- AddMetaData(object = acc_all_cells, metadata = cnsig, col.name = "copynumber")
acc_all_cells = SetIdent(object = acc_all_cells,value = "cell.type")

print_tab(plt = FeaturePlot(acc_all_cells, "copynumber",pt.size = 1,label = T,repel = T)+
            scale_colour_gradientn(colours=c("white","lightblue","orange","red","darkred"))
          ,title = "CNV UMAP",subtitle_num = 3)

CNV UMAP

Scale for ‘colour’ is already present. Adding another scale for ‘colour’, which will replace the existing scale.

NA

4 HMSC analysis

4.1 UMAP

hmsc_cancer_cells = FindClusters(object = hmsc_cancer_cells,verbose = F,resolution = 0.5)
DimPlot(object = hmsc_cancer_cells,pt.size = 2)

4.2 Scores

FeaturePlot(object = hmsc_cancer_cells,features = c("MYB","JAG1"),pt.size = 2)+
DimPlot(object = hmsc_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)

4.3 NMF

reticulate::repl_python()
from cnmf import cNMF
import pickle
nfeatures = "2K"
f = open('./Data/cNMF/HMSC_cNMF_harmony_2Kvargenes/cnmf_obj.pckl', 'rb')
cnmf_obj = pickle.load(f)
f.close()
quit
knitr::include_graphics("./Data/cNMF/HMSC_cNMF_harmony_2Kvargenes/HMSC_cNMF_harmony_2Kvargenes.k_selection.png")

reticulate::repl_python()
selected_k = 3
density_threshold = 0.1
cnmf_obj.consensus(k=selected_k, density_threshold=density_threshold,show_clustering=True)
usage_norm, gep_scores, gep_tpm, topgenes = cnmf_obj.load_results(K=selected_k, density_threshold=density_threshold)
quit
gep_scores = py$gep_scores
gep_tpm = py$gep_tpm
all_metagenes= py$usage_norm

4.4 Harmony results

# Make metagene names
for (i in 1:ncol(all_metagenes)) {
  colnames(all_metagenes)[i] = "metagene." %>% paste0(i)
}

#add each metagene to metadata
for (i in 1:ncol(all_metagenes)) {
  metage_metadata = all_metagenes %>% select(i)
  acc1_cancer_cells = AddMetaData(object = acc1_cancer_cells,metadata = metage_metadata)
}

Note: Using an external vector in selections is ambiguous. ℹ Use all_of(i) instead of i to silence this message. ℹ See https://tidyselect.r-lib.org/reference/faq-external-vector.html. This message is displayed once per session.

print_tab(plt = 
            FeaturePlot(object = acc1_cancer_cells,features = colnames(all_metagenes),combine = T),
          title = "metagenes expression",subtitle_num = toc_tabs_level)

metagenes expression

NA

4.5 Enrichment analysis by top 200 genes of each program


canonical_pathways = msigdbr(species = "Homo sapiens", category = "C2") %>% dplyr::filter(gs_subcat != "CGP") %>%  dplyr::distinct(gs_name, gene_symbol)

plt_list = list()
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),200) #take top top_genes_num
  res = genes_vec_enrichment(genes = top,background = rownames(gep_scores),homer = T,title = 
                    i,silent = T,return_all = T,custom_pathways = canonical_pathways)
   
  plt_list[[i]] = res$plt
}
gridExtra::grid.arrange(grobs = plt_list)

for (i in 1:ncol(gep_scores)) {
  ranked_vec = gep_scores %>% pull(i) %>%  setNames(rownames(gep_scores))
  hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = T)

  plt = hyp_dots(hyp_obj,merge = F)+ aes(size=abs(nes))
  print(plt)
}

library(ComplexHeatmap)
acc1_cancer_cells = SetIdent(object = acc1_cancer_cells,value = "seurat_clusters")
for (i in 1:ncol(gep_scores)) {
  top_genes = gep_scores  %>%  arrange(desc(gep_scores[i])) #sort by score a
  top = head(rownames(top_genes),50) #take top top_genes_num
  data = FetchData(object = acc1_cancer_cells,vars = top)%>% scale() %>% t() 
  metagene_data = FetchData(object = acc1_cancer_cells,vars = colnames(all_metagenes)[i])
  col_list = list(circlize::colorRamp2(c(0, 1), c("white", "red"))); names(col_list) = colnames(all_metagenes)[i]
  column_ha = HeatmapAnnotation(df = metagene_data,col = col_list)
  print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, top_annotation = 
                                  column_ha,name = "Z-score expression"))
    
  pdf(paste0("./Figures/NMF_top_genes_program",i,".pdf"))
  print(ComplexHeatmap::Heatmap(data,show_column_names = F,row_names_gp = grid::gpar(fontsize = 7),cluster_rows = F, top_annotation = 
                                  column_ha,name = "Z-score expression"))
  dev.off()
}

4.6 Lum Myo score

original_myo_genes = c( "TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI" )
FeaturePlot(hmsc_cancer_cells,features = original_myo_genes)

FeaturePlot(hmsc_cancer_cells,features = original_lum_genes)

acc_cancerCells_noACC1 = SetIdent(acc_cancerCells_noACC1,value = "patient.ident")
calculate_score(dataset = acc_cancerCells_noACC1,myo_genes = original_myo_genes,lum_genes = original_lum_genes)
correlation of lum score and myo score: -0.51
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

calculate_score.2 <- function(dataset,myo_genes,lum_genes,lum_threshold =1 , myo_threshold = -1) {
  myoscore=FetchData(object =dataset,vars =  myo_genes,slot = "data") %>% rowMeans()
  lescore=FetchData(object =dataset,vars =  lum_genes,slot = "data") %>% rowMeans()
  correlation = cor(lescore,myoscore) %>% round(digits = 2)
  message("correlation of lum score and myo score:" %>% paste(correlation))
  
  
  original_myo_genes = c("TP63", "TP73", "CAV1", "CDH3", "KRT5", "KRT14", "ACTA2", "TAGLN", "MYLK", "DKK3")
  original_lum_genes = c("KIT", "EHF", "ELF5", "KRT7", "CLDN3", "CLDN4", "CD24", "LGALS3", "LCN2", "SLPI")
  orig_myoscore=FetchData(object =dataset,vars =  original_myo_genes,slot = "data") %>% rowMeans()
  orig_lescore=FetchData(object =dataset,vars =  original_lum_genes,slot = "data") %>% rowMeans()
  correlation_to_original_lum = cor(orig_lescore,lescore) %>% round(digits = 2)
  correlation_to_original_myo = cor(orig_myoscore,myoscore) %>% round(digits = 2)

  message("correlation of lum score and original lum score:" %>% paste(correlation_to_original_lum))
  message("correlation of myo score and original myo score:" %>% paste(correlation_to_original_myo))

  dataset=AddMetaData(dataset,lescore-myoscore,"luminal_over_myo")
  print(
    FeaturePlot(object = dataset,features = "luminal_over_myo")
  )
  data = FetchData(object = dataset,vars = "luminal_over_myo")
  print(
    data %>% 
    ggplot(aes( x=luminal_over_myo)) + 
    geom_density() +ylab("Density")+theme(  axis.title=element_text(size=12,face="bold"))+ xlab("Luminal-Myoepithelial spectrum")
    )
  
lum_cells_num = subset(x = dataset,luminal_over_myo >(lum_threshold)) %>% ncol() /ncol(dataset)
myo_cells_num = subset(x = dataset,luminal_over_myo <(myo_threshold)) %>% ncol()/ncol(dataset)
df = data.frame(cell_type = c("myo_cells","lum_cells"),percentage = c(myo_cells_num,lum_cells_num))
ggplot(data=df, aes(x=cell_type, y=percentage)) +
  geom_bar(stat="identity") + ggtitle("ACC cell types")
}

4.7 Original score of ACC1

calculate_score.2(dataset = acc_pri,myo_genes = original_myo_genes,lum_genes = original_lum_genes,lum_threshold = 0,myo_threshold = 0)
correlation of lum score and myo score: -0.51
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

calculate_score(dataset = hmsc_cancer_cells,myo_genes = original_myo_genes,lum_genes = original_lum_genes,lum_threshold = 0,myo_threshold = 0)
correlation of lum score and myo score: -0.08
correlation of lum score and original lum score: 1
correlation of myo score and original myo score: 1

data = FetchData(object = hmsc_cancer_cells,vars = c(original_lum_genes))
a = cor(data)
ComplexHeatmap::Heatmap(matrix = cor(data),name = "pearson")

4.8 HPV

4.8.1 HPV UMAP

HPV33_P3 = fread("./Data/HPV33_P3.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P3.df = HPV33_P3 %>% mutate(
  plate = gsub(x =HPV33_P3$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "-P",replacement = ".P") 
  %>% gsub(pattern = "-",replacement = "_",)
  )
HPV33_P3.df = HPV33_P3.df %>% dplyr::filter(HPV33_P3.df$plate %in% colnames(hmsc_cancer_cells))
rownames(HPV33_P3.df)  <- HPV33_P3.df$plate
HPV33_P3.df$plate = NULL


HPV33_P2 = fread("./Data/HPV33_P2.txt",col.names = c("plate","reads")) %>% as.data.frame()
HPV33_P2.df = HPV33_P2 %>% mutate(
  plate = gsub(x =HPV33_P2$plate, replacement = "",pattern = "_.*$") 
  %>% gsub(pattern = "plate2-",replacement = "plate2_",)
  %>% gsub(pattern = "-",replacement = "\\.",)
  )
HPV33_P2.df = HPV33_P2.df %>% dplyr::filter(HPV33_P2.df$plate %in% colnames(hmsc_cancer_cells))
rownames(HPV33_P2.df)  <- HPV33_P2.df$plate
HPV33_P2.df$plate = NULL

HPV33 = rbind(HPV33_P3.df,HPV33_P2.df)
hmsc_cancer_cells = AddMetaData(object = hmsc_cancer_cells,metadata = HPV33,col.name = "HPV33.reads")
FeaturePlot(hmsc_cancer_cells,features = "HPV33.reads",max.cutoff = 10)


data = FetchData(object = hmsc_cancer_cells,vars = "HPV33.reads")

data = data %>% mutate("0 reads" = if_else(condition = HPV33.reads == 0,true = 1,false = 0))
data = data %>% mutate("1 reads" = if_else(condition = HPV33.reads == 1,true = 1,false = 0))
data = data %>% mutate("2 reads" = if_else(condition = HPV33.reads == 2,true = 1,false = 0))
data = data %>% mutate("3-23 reads" = if_else(condition = HPV33.reads >=3 &HPV33.reads  <24,true = 1,false = 0))
data = data %>% mutate("24+ reads" = if_else(condition = HPV33.reads >=24,true = 1,false = 0))
data = colSums(data[,2:ncol(data)]) %>% as.data.frame()
names(data)[1] = "count"
data = rownames_to_column(data,var = "bin")
data
ggplot(data=data, aes(x=factor(bin,levels = c("0 reads","1 reads","2 reads","3-23 reads","24+ reads")), y=count)) +
  geom_bar(stat="identity", fill="steelblue") + xlab("HPV Reads")+ theme_minimal()+
  geom_text(aes(label=count), vjust=-0.5, color="black", size=3.5)

hpv33_positive = HPV33 %>% dplyr::mutate(hpv33_positive = case_when(reads >= 10 ~ "positive",
                                                                    reads < 10 ~ "negative")
)



hpv33_positive$reads = NULL
hmsc_cancer_cells = AddMetaData(object = hmsc_cancer_cells,metadata = hpv33_positive)
DimPlot(object = hmsc_cancer_cells,group.by  = c("hpv33_positive"),pt.size = 2)+
FeaturePlot(object = hmsc_cancer_cells,features = "MYB",pt.size = 2)

library(biomaRt)
ensembl = useEnsembl(biomart="ensembl", dataset="hsapiens_gene_ensembl")

4.8.2 DEG LR latent vars plate

DefaultAssay(hmsc_cancer_cells) = "integrated"
library("biomaRt")
# mart <- useMart(biomart="ensembl", dataset="hsapiens_gene_ensembl")
# all_coding_genes <- getBM(attributes = c( "hgnc_symbol"), filters = c("biotype"), values = list(biotype="protein_coding"), mart = mart)

features = VariableFeatures(hmsc_cancer_cells)
features = hmsc_cancer_cells@assays$RNA@data %>% rowMeans() %>% sort(decreasing = T) %>% head(3000) %>% names()
# features  = intersect(features, VariableFeatures(hmsc_cancer_cells) )
# features  = intersect(features, all_coding_genes[,1] )

acc_deg <-
  FindMarkers(
    hmsc_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.1,
    min.pct = 0.1,
    only.pos = F,
    mean.fxn = function(x) {
      return(log(rowMeans(x) + 1, base = 2)) # change func to calculate logFC in log space data (default to exponent data)
      # return(log(rowMeans(expm1(x)) + 1, base = 2))

    }
  )

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~09s          
  |++                                                | 2 % ~08s          
  |++                                                | 3 % ~11s          
  |+++                                               | 4 % ~10s          
  |+++                                               | 5 % ~10s          
  |++++                                              | 6 % ~09s          
  |++++                                              | 7 % ~09s          
  |+++++                                             | 8 % ~09s          
  |+++++                                             | 9 % ~09s          
  |++++++                                            | 10% ~08s          
  |++++++                                            | 11% ~08s          
  |+++++++                                           | 12% ~08s          
  |+++++++                                           | 13% ~08s          
  |++++++++                                          | 14% ~08s          
  |++++++++                                          | 15% ~08s          
  |+++++++++                                         | 16% ~07s          
  |+++++++++                                         | 17% ~07s          
  |++++++++++                                        | 18% ~07s          
  |++++++++++                                        | 19% ~08s          
  |+++++++++++                                       | 20% ~07s          
  |+++++++++++                                       | 21% ~07s          
  |++++++++++++                                      | 22% ~07s          
  |++++++++++++                                      | 23% ~07s          
  |+++++++++++++                                     | 24% ~07s          
  |+++++++++++++                                     | 26% ~07s          
  |++++++++++++++                                    | 27% ~07s          
  |++++++++++++++                                    | 28% ~07s          
  |+++++++++++++++                                   | 29% ~06s          
  |+++++++++++++++                                   | 30% ~06s          
  |++++++++++++++++                                  | 31% ~06s          
  |++++++++++++++++                                  | 32% ~06s          
  |+++++++++++++++++                                 | 33% ~06s          
  |+++++++++++++++++                                 | 34% ~06s          
  |++++++++++++++++++                                | 35% ~06s          
  |++++++++++++++++++                                | 36% ~06s          
  |+++++++++++++++++++                               | 37% ~06s          
  |+++++++++++++++++++                               | 38% ~06s          
  |++++++++++++++++++++                              | 39% ~06s          
  |++++++++++++++++++++                              | 40% ~05s          
  |+++++++++++++++++++++                             | 41% ~05s          
  |+++++++++++++++++++++                             | 42% ~05s          
  |++++++++++++++++++++++                            | 43% ~05s          
  |++++++++++++++++++++++                            | 44% ~05s          
  |+++++++++++++++++++++++                           | 45% ~05s          
  |+++++++++++++++++++++++                           | 46% ~05s          
  |++++++++++++++++++++++++                          | 47% ~05s          
  |++++++++++++++++++++++++                          | 48% ~05s          
  |+++++++++++++++++++++++++                         | 49% ~05s          
  |+++++++++++++++++++++++++                         | 50% ~04s          
  |++++++++++++++++++++++++++                        | 51% ~04s          
  |+++++++++++++++++++++++++++                       | 52% ~04s          
  |+++++++++++++++++++++++++++                       | 53% ~04s          
  |++++++++++++++++++++++++++++                      | 54% ~04s          
  |++++++++++++++++++++++++++++                      | 55% ~04s          
  |+++++++++++++++++++++++++++++                     | 56% ~04s          
  |+++++++++++++++++++++++++++++                     | 57% ~04s          
  |++++++++++++++++++++++++++++++                    | 58% ~04s          
  |++++++++++++++++++++++++++++++                    | 59% ~04s          
  |+++++++++++++++++++++++++++++++                   | 60% ~04s          
  |+++++++++++++++++++++++++++++++                   | 61% ~04s          
  |++++++++++++++++++++++++++++++++                  | 62% ~03s          
  |++++++++++++++++++++++++++++++++                  | 63% ~03s          
  |+++++++++++++++++++++++++++++++++                 | 64% ~03s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~03s          
  |++++++++++++++++++++++++++++++++++                | 66% ~03s          
  |++++++++++++++++++++++++++++++++++                | 67% ~03s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~03s          
  |+++++++++++++++++++++++++++++++++++               | 69% ~03s          
  |++++++++++++++++++++++++++++++++++++              | 70% ~03s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~03s          
  |+++++++++++++++++++++++++++++++++++++             | 72% ~02s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~02s          
  |++++++++++++++++++++++++++++++++++++++            | 74% ~02s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~02s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~02s          
  |+++++++++++++++++++++++++++++++++++++++           | 78% ~02s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~02s          
  |++++++++++++++++++++++++++++++++++++++++          | 80% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~02s          
  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~02s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 90% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~01s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~01s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=09s  
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
ranked_vec = acc_deg[,"avg_log2FC"]%>% setNames(rownames(acc_deg)) %>% na.omit() # make named vector

hyp_obj <-hypeR_fgsea(signature = ranked_vec,genesets = genesets,up_only = F)
hyp_dots(hyp_obj,merge = F)×–
acc_deg
acc_deg[c("MYB","JAG1"),]
NA

volcano plot log2(mean logTPM HPV+) - log2(mean logTPM HPV-)

volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)


acc_deg2 = acc_deg %>% mutate(avg_log2FC = exp(avg_log2FC))
volcano_plot(de_genes = acc_deg2,fc_cutoff = 2**(1.3), fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)

volcano plot log2(mean logTPM HPV+) - log2(mean logTPM HPV-)


acc_deg <-
  FindMarkers(
    acc1_cancer_cells,
    ident.1 = "positive",
    ident.2 = "negative",
    features = features,
    densify = T,
    assay = "RNA",
    test.use = "LR",
    latent.vars = "plate",
    logfc.threshold = 0.35,
    min.pct = 0.1,
    mean.fxn = function(x) {
      return(rowMeans(x) + 1) # change func to calculate logFC in log space data (default to exponent data)
    }
  )
acc_deg$fdr<-p.adjust(p = as.vector(acc_deg$p_val) ,method = "fdr" )
acc_deg[c("MYB","JAG1"),]

volcano plot (mean logTPM HPV+) - (mean logTPM HPV-)

volcano_plot(de_genes = acc_deg,fc_cutoff = 1.3, fdr_cutoff = 0.1,show_gene_names = c("MYB","JAG1"),ident1 = "HPV33 positive",ident2 = "HPV33 negative",top_genes_text = 5)+xlab("avg diff")
Warning in de_genes$delabel[up_genes] <- `*vtmp*` :
  number of items to replace is not a multiple of replacement length

4.8.3 HPV vs genes

notch_genes = c("JAG1","JAG2","NOTCH3","NOTCH2","NOTCH1","DLL1","MYB","HES4","HEY1","HEY2","NRARP")
for (gene  in notch_genes) {
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive",gene)) 
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = gene,
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(gene)
  print_tab(p,title = gene)
}
##   JAG1 {.unnumbered }  

 

##   JAG2 {.unnumbered }  

 

##   NOTCH3 {.unnumbered }  

 

##   NOTCH2 {.unnumbered }  

 

##   NOTCH1 {.unnumbered }  

 

##   DLL1 {.unnumbered }  

 

##   MYB {.unnumbered }  

 

##   HES4 {.unnumbered }  

 

##   HEY1 {.unnumbered }  

 

##   HEY2 {.unnumbered }  

 

##   NRARP {.unnumbered }  

NA
notch_targets = c("NOTCH3","HES4","HEY1","HEY2","NRARP") 
notch_ligand = c("JAG1","JAG2","DLL1")
notch_genes = list(notch_targets = notch_targets,notch_ligand = notch_ligand)
for (i  in 1:length(notch_genes)) {
  genes = notch_genes[[i]]
  name = names( notch_genes)[i]
  myb_vs_hpv = FetchData(object = acc1_cancer_cells,vars = c(genes)) %>% rowMeans()
  myb_vs_hpv = myb_vs_hpv %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("hpv33_positive")))
  colnames(myb_vs_hpv)[1] = "gene_set"
  myb_vs_hpv$hpv33_positive = paste("HPV33",myb_vs_hpv$hpv33_positiv)

  p = ggboxplot(myb_vs_hpv, x = "hpv33_positive", y = "gene_set",
            palette = "jco",
            add = "jitter")+ stat_compare_means(method = "wilcox.test",comparisons = list(c("HPV33 positive","HPV33 negative")))+ stat_summary(fun.data = function(x) data.frame(y=max(x)*1.2, label = paste("Mean=",round(mean(x),digits = 2))), geom="text") +ylab("log2(gene)")+ggtitle(name)
 print(p)
}
  cor_data = FetchData(object = acc1_cancer_cells,vars = c("MYB","myo_score"))
ggplot(cor_data, aes(x=MYB, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG1","myo_score"))
ggplot(cor_data, aes(x=JAG1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("JAG2","myo_score"))
ggplot(cor_data, aes(x=JAG2, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()

  cor_data = FetchData(object = acc1_cancer_cells,vars = c("DLL1","myo_score"))
ggplot(cor_data, aes(x=DLL1, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()


  cor_data = FetchData(object = acc1_cancer_cells,vars = notch_targets) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_targets"

  ggplot(cor_data, aes(x=notch_targets, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
  
    cor_data = FetchData(object = acc1_cancer_cells,vars = notch_ligand) %>% rowMeans()
  cor_data = cor_data %>% cbind(FetchData(object = acc1_cancer_cells,vars = c("myo_score")))
  colnames(cor_data)[1] = "notch_ligand"

  ggplot(cor_data, aes(x=notch_ligand, y=myo_score)) + 
    stat_cor(method = "pearson")+
    geom_smooth(method=lm)  +
  geom_point()
  
notch_score = FetchData(object = all_acc_cancer_cells,vars = notch_targets) %>% rowMeans()
all_acc_cancer_cells  = AddMetaData(object = all_acc_cancer_cells,metadata = notch_score,col.name = "notch_score")
FeaturePlot(object = all_acc_cancer_cells,features = "notch_score" )
myo_markers = c("TP63", "TP73", "KRT14", "CDH3")
score = FetchData(object = acc1_cancer_cells,vars = myo_markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "myo_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "myo_markers_score",pt.size = 2 )


markers = c("CLDN3", "ANXA8", "EHF", "KIT")
score = FetchData(object = acc1_cancer_cells,vars = markers) %>% rowMeans()
acc1_cancer_cells  = AddMetaData(object = acc1_cancer_cells,metadata = score,col.name = "lum_markers_score")
FeaturePlot(object = acc1_cancer_cells,features = "lum_markers_score" ,pt.size = 2 )
LS0tCnRpdGxlOiAnYHIgcnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGggJT4lIGJhc2VuYW1lKCkgJT4lIGdzdWIocGF0dGVybiA9ICJcXC5SbWQiLHJlcGxhY2VtZW50ID0gIiIpYCcgCmF1dGhvcjogIkF2aXNoYWkgV2l6ZWwiCmRhdGU6ICdgciBTeXMudGltZSgpYCcKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19jb2xsYXBzZTogeWVzCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IEZBTFNFCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19kZXB0aDogMgotLS0KCgoKIyBGdW5jdGlvbnMKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAiREVHX2Z1bmN0aW9ucyIsdmVyc2lvbiA9ICIwLjIuNTMiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gIkhNU0NfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuMS4xNCIsc2NyaXB0X25hbWUgPSAiZnVuY3Rpb25zLlIiKQpzb3VyY2VfZnJvbV9naXRodWIocmVwb3NpdG95ID0gImNOTUZfZnVuY3Rpb25zIix2ZXJzaW9uID0gIjAuNC4wNCIsc2NyaXB0X25hbWUgPSAiY25tZl9mdW5jdGlvbnNfVjMuUiIpCnNvdXJjZV9mcm9tX2dpdGh1YihyZXBvc2l0b3kgPSAic2NfZ2VuZXJhbF9mdW5jdGlvbnMiLHZlcnNpb24gPSAiMC4xLjM0IixzY3JpcHRfbmFtZSA9ICJmdW5jdGlvbnMuUiIpCmxpYnJhcnkoaHlwZVIpCgpgYGAKCiMgRGF0YQoKYGBge3J9Cmhtc2NfY2FuY2VyX2NlbGxzID0gcmVhZFJEUygiLi9EYXRhL2FjYzFfY2FuY2VyX2NlbGxzXzI1MDBmZWF0dXJlc19pbnRlZ3JhdGVkX1Y1LlJEUyIpCmhtc2NfYWNjX3ByaV9jYW5jZXIgPSByZWFkUkRTKCIuL0RhdGEvaG1zY19hY2NfcHJpX2NhbmNlcl9wcm9jZXNzZWRfVjYuUkRTIikKYWNjX3ByaSA9IHN1YnNldChobXNjX2FjY19wcmlfY2FuY2VyLHN1YnNldCA9IHBhdGllbnQuaWRlbnQgIT0gIkhNU0MiKQoKCmFsbF9jZWxscyA9IHJlYWRSRFMoIi4vRGF0YS9hY2NfdHBtX25Db3VudF9taXRvX25vMTQ2XzE1a193aXRoX0FDQzFfVjIuUkRTIikKZ2VuZXNldHNfaCAgPWdldEdtdCgiLi9EYXRhL2guYWxsLnY3LjAuc3ltYm9scy5wbHVzY2MuZ210IikKCiMgbHVtaW5hbF9wYXRod2F5cyA9IGMoIkNIQVJBRkVfQlJFQVNUX0NBTkNFUl9MVU1JTkFMX1ZTX0JBU0FMX0ROIiwiQ0hBUkFGRV9CUkVBU1RfQ0FOQ0VSX0xVTUlOQUxfVlNfQkFTQUxfVVAiLCJDSEFSQUZFX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9WU19NRVNFTkNIWU1BTF9ETiIsIkNIQVJBRkVfQlJFQVNUX0NBTkNFUl9MVU1JTkFMX1ZTX01FU0VOQ0hZTUFMX1VQIiwiSFVQRVJfQlJFQVNUX0JBU0FMX1ZTX0xVTUlOQUxfRE4iLCJMSU1fTUFNTUFSWV9MVU1JTkFMX1BST0dFTklUT1JfVVAiLCJTTUlEX0JSRUFTVF9DQU5DRVJfTFVNSU5BTF9CX1VQIiApCiMgCiMgIyBhZGQgbHVtaW5hbCBwYXRod2F5cwojIGx1bWluYWxfZ3MgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgZHBseXI6OmZpbHRlcihnc19uYW1lICVpbiUgbHVtaW5hbF9wYXRod2F5cyklPiUgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmBgYAoKCgoKIyBITVNDIHZzIEFDQwoKIyMgVU1BUAoKYGBge3J9CkRpbVBsb3QoaG1zY19hY2NfcHJpX2NhbmNlcixncm91cC5ieSA9ICJwYXRpZW50LmlkZW50IixsYWJlbCA9IFQpCmBgYAoKYGBge3J9CkZlYXR1cmVQbG90KG9iamVjdCA9IGhtc2NfYWNjX3ByaV9jYW5jZXIsZmVhdHVyZXMgPSBjKCJNWUIiKSxwdC5zaXplID0gMSkKRmVhdHVyZVBsb3Qob2JqZWN0ID0gaG1zY19hY2NfcHJpX2NhbmNlcixmZWF0dXJlcyA9IGMoImtheWVfYWNjX3Njb3JlIikscHQuc2l6ZSA9IDEpCgpgYGAKCgoKYGBge3J9CnBkZigiLi9GaWd1cmVzL2theWVfYWNjX3Njb3JlX0FsbENhbmNlckNlbGxzLnBkZiIpCkZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gYygia2F5ZV9hY2Nfc2NvcmUiKSxwdC5zaXplID0gMSkKZGV2Lm9mZigpCmBgYAoKIyMgZW5yaWNobWVudCBhbmFseXNpcyAKCmBgYHtyIGZpZy53aWR0aD04LCBlY2hvPVRSVUUscmVzdWx0cz0naGlkZScsZmlnLmtlZXA9J2FsbCd9Cmhtc2NfYWNjX3ByaV9jYW5jZXIgPSBTZXRJZGVudChobXNjX2FjY19wcmlfY2FuY2VyLCB2YWx1ZSA9InBhdGllbnQuaWRlbnQiKQphY2NfZGVnIDwtCiAgRmluZE1hcmtlcnMoCiAgICBobXNjX2FjY19wcmlfY2FuY2VyLAogICAgaWRlbnQuMSA9ICJITVNDIiwKICAgIGZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhobXNjX2FjY19wcmlfY2FuY2VyKSwKICAgIGRlbnNpZnkgPSBULAogICAgYXNzYXkgPSAiUk5BIiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4obG9nKHJvd01lYW5zKHgpICsgMSwgYmFzZSA9IDIpKSAjIGNoYW5nZSBmdW4gdG8gY2FsY3VsYXRlIGxvZ0ZDIGluIGxvZyBzcGFjZSBkYXRhIChkZWZhdWx0IHRvIGV4cG9uZW50IGRhdGEpCiAgICB9CiAgKQoKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMywgcmVzdWx0cz0nYXNpcyd9CnJhbmtlZF92ZWMgPSBhY2NfZGVnWywiYXZnX2xvZzJGQyJdJT4lIHNldE5hbWVzKHJvd25hbWVzKGFjY19kZWcpKSAlPiUgbmEub21pdCgpICMgbWFrZSBuYW1lZCB2ZWN0b3IKCmh5cF9vYmogPC1oeXBlUl9mZ3NlYShzaWduYXR1cmUgPSByYW5rZWRfdmVjLGdlbmVzZXRzID0gZ2VuZUlkcyhnZW5lc2V0c19oKSx1cF9vbmx5ID0gRikKCnBsdCA9IGh5cF9kb3RzKGh5cF9vYmosbWVyZ2UgPSBGKQpwbHQxID0gcGx0JHVwKyBhZXMoc2l6ZT1uZXMpK2dndGl0bGUoInVwIGluIEhNU0MiKQpwbHQyID0gcGx0JGRuKyBhZXMoc2l6ZT1hYnMobmVzKSkrZ2d0aXRsZSgidXAgaW4gQUNDIikKcGx0MStwbHQyCmBgYAoKIyMgQ2VsbCBjeWNsZSBzY29yZSAgey50YWJzZXR9CgpgYGB7cn0KRGVmYXVsdEFzc2F5KGhtc2NfY2FuY2VyX2NlbGxzKSA9ICJSTkEiCmBgYAoKYGBge3J9CmhhbGxtYXJrX25hbWUgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIgphY2NfcHJpID0gU2NhbGVEYXRhKG9iamVjdCA9IGFjY19wcmksZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKGFjY19wcmksYXNzYXkgPSAiUk5BIikpCmdlbmVJZHM9IGdlbmVzZXRzX2hbW2hhbGxtYXJrX25hbWVdXUBnZW5lSWRzICU+JSBpbnRlcnNlY3QoVmFyaWFibGVGZWF0dXJlcyhhY2NfcHJpLGFzc2F5ID0gIlJOQSIpKSAKc2NvcmUgPC0gYXBwbHkoYWNjX3ByaUBhc3NheXMkUk5BQHNjYWxlLmRhdGFbZ2VuZUlkcyxdLDIsbWVhbikKYWNjX3ByaT1BZGRNZXRhRGF0YShhY2NfcHJpLHNjb3JlLGhhbGxtYXJrX25hbWUpCgpobXNjX2NhbmNlcl9jZWxscyA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLG5mZWF0dXJlcyA9IDE1MDAwKQpobXNjX2NhbmNlcl9jZWxscyA9IFNjYWxlRGF0YShvYmplY3QgPSBobXNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoaG1zY19jYW5jZXJfY2VsbHMpKQpnZW5lSWRzPSBnZW5lc2V0c19oW1toYWxsbWFya19uYW1lXV1AZ2VuZUlkcyAlPiUgaW50ZXJzZWN0KFZhcmlhYmxlRmVhdHVyZXMoaG1zY19jYW5jZXJfY2VsbHMpKSAKc2NvcmUgPC0gYXBwbHkoaG1zY19jYW5jZXJfY2VsbHNAYXNzYXlzJFJOQUBzY2FsZS5kYXRhW2dlbmVJZHMsXSwyLG1lYW4pCmhtc2NfY2FuY2VyX2NlbGxzPUFkZE1ldGFEYXRhKGhtc2NfY2FuY2VyX2NlbGxzLHNjb3JlLGhhbGxtYXJrX25hbWUpCgpgYGAKCmBgYHtyIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CmFjY19jY19zY29yZXMgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjX3ByaSx2YXJzID0gIkdPX01JVE9USUNfQ0VMTF9DWUNMRSIpCmhtc2NfY2Nfc2NvcmVzID0gRmV0Y2hEYXRhKG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLHZhcnMgPSAiR09fTUlUT1RJQ19DRUxMX0NZQ0xFIikKCmRpc3RyaWJ1dGlvbnNfcGx0ID0gZ2dwbG90KCkgKwogIGdlb21fZGVuc2l0eShhZXMoR09fTUlUT1RJQ19DRUxMX0NZQ0xFLCBmaWxsID0gIkFDQyIpLCBhbHBoYSA9IC4yLCBkYXRhID0gYWNjX2NjX3Njb3JlcykgKwogIGdlb21fZGVuc2l0eShhZXMoR09fTUlUT1RJQ19DRUxMX0NZQ0xFLCBmaWxsID0gIkhNU0MiKSwgYWxwaGEgPSAuMiwgZGF0YSA9IGhtc2NfY2Nfc2NvcmVzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJEYXRhc2V0IiwgdmFsdWVzID0gYyhBQ0MgPSAicmVkIiwgSE1TQyA9ICJncmVlbiIpKSsgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0wLjMpLAogICAgICAgICAgICBjb2xvcj0iYmx1ZSIsIGxpbmV0eXBlPSJkYXNoZWQiLCBzaXplPTEpICtnZ3RpdGxlKCInR09fTUlUT1RJQ19DRUxMX0NZQ0xFJyAgc2NvcmUgZGlzdHJpYnV0aW9uIikKCnByaW50X3RhYihwbHQgPSBkaXN0cmlidXRpb25zX3BsdCx0aXRsZSA9ICJzY29yZSBkaXN0cmlidXRpb24iLHN1YnRpdGxlX251bSA9IDMpCgpgYGAKCgpgYGB7ciBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpobXNjX2NjX2NlbGxzID0gKHN1bShobXNjX2NhbmNlcl9jZWxsc0BtZXRhLmRhdGFbW2hhbGxtYXJrX25hbWVdXT4gMC4zKSAvbmNvbChobXNjX2NhbmNlcl9jZWxscykpICU+JSByb3VuZChkaWdpdHMgPSAzKSoxMDAKYWNjX2NjX2NlbGxzID0gKHN1bShhY2NfcHJpQG1ldGEuZGF0YVtbaGFsbG1hcmtfbmFtZV1dPiAwLjMpL25jb2woYWNjX3ByaSkpICU+JSByb3VuZChkaWdpdHMgPSAzKSoxMDAKZGYgPSBkYXRhLmZyYW1lKERhdGFzZXQgPSBjKCJITVNDIiwiQUNDIiksIGN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSA9IGMoaG1zY19jY19jZWxscyxhY2NfY2NfY2VsbHMpKQpjeWNsaW5nX2NlbGxzX3BsdCA9IGdncGxvdChkYXRhPWRmLCBhZXMoeD1EYXRhc2V0LCB5PWN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWN5Y2xpbmdfY2VsbHNfcGVyY2VudGFnZSksIHZqdXN0PTAsIGNvbG9yPSJibGFjayIsIHNpemU9My41KSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK3lsYWIoIiAlIGN5Y2xpbmcgY2VsbHMiKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9InN0ZWVsYmx1ZSIpKwogIHRoZW1lX21pbmltYWwoKSArIGdndGl0bGUoIkN5Y2xpbmcgY2VsbHMgY291bnQiKQoKcHJpbnRfdGFiKHBsdCA9IGN5Y2xpbmdfY2VsbHNfcGx0LHRpdGxlID0gIiMgY3ljbGluZyBjZWxscyIsc3VidGl0bGVfbnVtID0gMykKYGBgCmBgYHtyfQpwZGYoZmlsZSA9ICIuL0ZpZ3VyZXMvQ0NfZGlzdHJpYnV0aW9ucy5wZGYiKQpkaXN0cmlidXRpb25zX3BsdApkZXYub2ZmKCkKCnBkZihmaWxlID0gIi4vRmlndXJlcy9jeWNsaW5nX2NlbGxzLnBkZiIpCmN5Y2xpbmdfY2VsbHNfcGx0CmRldi5vZmYoKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgcmVzdWx0cz0nYXNpcyd9CnByaW50X3RhYihwbHQgPSAKICAgICAgICAgICAgRmVhdHVyZVBsb3QoaG1zY19hY2NfcHJpX2NhbmNlcixmZWF0dXJlcyA9IGMoIk1LSTY3IiwiQ0RLMSIsIk1DTTIiLCJDREMyMCIpKQogICAgICAgICAgLHRpdGxlID0gIkNDIGdlbmVzIixzdWJ0aXRsZV9udW0gPSAzKQpgYGAKCiMjIEN5Y2xpbmcgY2VsbHMgZmlsdGVyaW5nIHsudGFic2V0fQpgYGB7ciB3YXJuaW5nPUZBTFNFfQojYWRkIHNjb3JlIHRvIGFsbCBhY2MgY2FuY2VyIGNlbGxzCiMgZ2VuZUlkcz0gZ2VuZXNldHNbW2hhbGxtYXJrX25hbWVdXUBnZW5lSWRzICU+JSBpbnRlcnNlY3QoVmFyaWFibGVGZWF0dXJlcyhhbGxfYWNjX2NhbmNlcl9jZWxscyxhc3NheSA9ICJpbnRlZ3JhdGVkIikpIAojIHNjb3JlIDwtIGFwcGx5KGFsbF9hY2NfY2FuY2VyX2NlbGxzQGFzc2F5cyRpbnRlZ3JhdGVkQHNjYWxlLmRhdGFbZ2VuZUlkcyxdLDIsbWVhbikKCiNhZGQgc2NvcmUgdG8gYWxsIGFjYyBjYW5jZXIgY2VsbHMKY2NfYWxsID0gYyhhY2NfcHJpJEdPX01JVE9USUNfQ0VMTF9DWUNMRSwgaG1zY19jYW5jZXJfY2VsbHMkR09fTUlUT1RJQ19DRUxMX0NZQ0xFKSAlPiUgYXMuZGF0YS5mcmFtZSgpCmhtc2NfYWNjX3ByaV9jYW5jZXI9QWRkTWV0YURhdGEoaG1zY19hY2NfcHJpX2NhbmNlcixjY19hbGwsaGFsbG1hcmtfbmFtZSkKCiNmaWx0ZXI6CmFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQ9aG1zY19hY2NfcHJpX2NhbmNlclssaG1zY19hY2NfcHJpX2NhbmNlckBtZXRhLmRhdGFbW2hhbGxtYXJrX25hbWVdXTwgMC4zXQoKCm1pbl90aHJlc2hvbGQgPSBtaW4oaG1zY19hY2NfcHJpX2NhbmNlciRHT19NSVRPVElDX0NFTExfQ1lDTEUpCm1heF90aHJlc2hvbGQgPSBtYXgoaG1zY19hY2NfcHJpX2NhbmNlciRHT19NSVRPVElDX0NFTExfQ1lDTEUpCmBgYAoKYGBge3IsIHJlc3VsdHM9J2FzaXMnfQpsaWJyYXJ5KHZpcmlkaXMpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gaG1zY19hY2NfcHJpX2NhbmNlcixmZWF0dXJlcyA9IGhhbGxtYXJrX25hbWUpICsgZ2d0aXRsZSgiQmVmb3JlIGNjIGZpbHRlcmluZyIpICYKICAgICAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBwbGFzbWEobiA9IDEwLCBkaXJlY3Rpb24gPSAtMSksIGxpbWl0cyA9IGMobWluX3RocmVzaG9sZCwgbWF4X3RocmVzaG9sZCkpCiAgICAgICAgICAsdGl0bGUgPSAiQmVmb3JlIENDIGZpbHRlcmluZyIsc3VidGl0bGVfbnVtID0gMykKCgpwcmludF90YWIocGx0ID0gCiAgICAgICAgICAgIEZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsZmVhdHVyZXMgPSBoYWxsbWFya19uYW1lKSArIGdndGl0bGUoIkFmdGVyIGNjIGZpbHRlcmluZyIpICYKICAgICAgICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG91cnMgPSBwbGFzbWEobiA9IDEwLCBkaXJlY3Rpb24gPSAtMSksIGxpbWl0cyA9IGMobWluX3RocmVzaG9sZCwgbWF4X3RocmVzaG9sZCkpCiAgICAgICAgICAsdGl0bGUgPSAiQWZ0ZXIgQ0MgZmlsdGVyaW5nIiAsc3VidGl0bGVfbnVtID0gMykKCmBgYAoKCgojIyBERUcKCmBgYHtyIGZpZy53aWR0aD04LCBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnLGZpZy5rZWVwPSdhbGwnfQphbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkID0gU2V0SWRlbnQoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwgdmFsdWUgPSJwYXRpZW50LmlkZW50IikKYWNjX2RlZyA8LQogIEZpbmRNYXJrZXJzKAogICAgYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwKICAgIGlkZW50LjEgPSAiSE1TQyIsCiAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCksCiAgICBkZW5zaWZ5ID0gVCwKICAgIHZlcmJvc2UgPSBULAogICAgc2xvdCA9ICJkYXRhIiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4obG9nKHJvd01lYW5zKHgpICsgMSxiYXNlID0gMikpICMgY2hhbmdlIGZ1bmMgdG8gY2FsY3VsYXRlIGxvZ0ZDIGluIGxvZyBzcGFjZSBkYXRhIChkZWZhdWx0IHRvIGV4cG9uZW50IGRhdGEpCiAgICB9LAogICAgYXNzYXkgPSAiUk5BIgogICkKYGBgCgoKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEzLCByZXN1bHRzPSdhc2lzJ30KbGlicmFyeShoeXBlUikKZ2VuZXNldHMgPC0gbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJIIikgJT4lIGFwcGVuZCggbXNpZ2RiX2Rvd25sb2FkKCJIb21vIHNhcGllbnMiLGNhdGVnb3J5PSJDMiIsc3ViY2F0ZWdvcnkgPSAiQ1A6S0VHRyIpKQpyYW5rZWRfdmVjID0gYWNjX2RlZ1ssImF2Z19sb2cyRkMiXSU+JSBzZXROYW1lcyhyb3duYW1lcyhhY2NfZGVnKSkgJT4lIG5hLm9taXQoKSAjIG1ha2UgbmFtZWQgdmVjdG9yCgpoeXBfb2JqIDwtaHlwZVJfZmdzZWEoc2lnbmF0dXJlID0gcmFua2VkX3ZlYyxnZW5lc2V0cyA9IGdlbmVJZHMoZ2VuZXNldHNfaCksdXBfb25seSA9IEYpCgpwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikKcGx0MSA9IHBsdCR1cCsgYWVzKHNpemU9bmVzKStnZ3RpdGxlKCJ1cCBpbiBITVNDIikKcGx0MiA9IHBsdCRkbisgYWVzKHNpemU9YWJzKG5lcykpK2dndGl0bGUoInVwIGluIEFDQyIpCnBsdDErcGx0MgoKYGBgCgoKCgpgYGB7cn0KcGRmKGZpbGUgPSAiLi9GaWd1cmVzL0FDQ192c19ITVNDX0dTRUEucGRmIix3aWR0aCA9IDEzLGhlaWdodCA9IDYpCnBsdDMKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnZvbGNhbm9fcGxvdChkZV9nZW5lcyA9IGFjY19kZWcsZmRyX2N1dG9mZiA9IDAuMDUsZmNfY3V0b2ZmID0gMiwgaWRlbnQxID0gIkhNU0MiLGlkZW50MiA9ICJBQ0MiLHRvcF9nZW5lc190ZXh0ID0gNCkKYGBgCgoKCgoKYGBge3J9CnBkZigiLi9GaWd1cmVzL3ZvbGNhbm9fcGxvdF9BQ0NfVlNfSE1TQy5wZGYiKQp2b2xjYW5vX3Bsb3QoZGVfZ2VuZXMgPSBhY2NfZGVnLGZkcl9jdXRvZmYgPSAwLjA1LGZjX2N1dG9mZiA9IDIsIGlkZW50MSA9ICJITVNDIixpZGVudDIgPSAiQUNDIix0b3BfZ2VuZXNfdGV4dCA9IDQpCmRldi5vZmYoKQoKcGRmKCIuL0ZpZ3VyZXMvRW5yaWNobWVudF9hbmFseXNpc19BQ0NfVlNfSE1TQy5wZGYiKQpwbHQxK3BsdDIKZGV2Lm9mZigpCgpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CnRvcF9obXNjX2dlbmVzID0gYWNjX2RlZyAlPiUgZHBseXI6OmZpbHRlcihhdmdfbG9nMkZDID4gMCkgJT4lICBzbGljZV9taW4obiA9IDEwLG9yZGVyX2J5ID0gcF92YWxfYWRqKSAlPiUgcm93bmFtZXMoKQp0b3BfYWNjX2dlbmVzID0gYWNjX2RlZyAlPiUgZHBseXI6OmZpbHRlcihhdmdfbG9nMkZDIDwgMCkgJT4lICBzbGljZV9taW4obiA9IDEwLG9yZGVyX2J5ID0gcF92YWxfYWRqKSAlPiUgcm93bmFtZXMoKQphbGxfdG9wX2RlZyA9IGModG9wX2htc2NfZ2VuZXMsdG9wX2FjY19nZW5lcykKCmFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQkY2FuY2VyX3R5cGUgPSBhbGxfYWNjX2NhbmNlcl9jZWxsc19jY0ZpbHRlcmVkJHBhdGllbnQuaWRlbnQgJT4lIGdzdWIocGF0dGVybiA9ICJBQ0MuKiIscmVwbGFjZW1lbnQgPSAiQUNDIikKY2FuY2VyX3R5cGUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHNfY2NGaWx0ZXJlZCwgdmFycyA9ICJjYW5jZXJfdHlwZSIpCiMgY29sX2xpc3QgPSBsaXN0KGNpcmNsaXplOjpjb2xvclJhbXAyKGMoMCwgMSksIGMoIndoaXRlIiwgInJlZCIpKSk7IG5hbWVzKGNvbF9saXN0KSA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldCmNvbHVtbl9oYSA9IEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gY2FuY2VyX3R5cGUpCgpkYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzX2NjRmlsdGVyZWQsdmFycyA9IGFsbF90b3BfZGVnLHNsb3QgPSAic2NhbGUuZGF0YSIpICU+JSB0KCkKCnByaW50KENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKGRhdGEsc2hvd19jb2x1bW5fbmFtZXMgPSBGLHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSA3KSxjbHVzdGVyX3Jvd3MgPSBGLCAsbmFtZSA9ICJaLXNjb3JlIGV4cHJlc3Npb24iLGNsdXN0ZXJfY29sdW1ucyA9IEYsdG9wX2Fubm90YXRpb24gPSBjb2x1bW5faGEpKQogIAoKYGBgCgoKCiMjIENOViBwbG90IHsudGFic2V0fQpgYGB7cn0KIyBjcmVhdGUgZXhwcmVzc2lvbiBtYXRyaXggb2YgYWNjICsgbm9ybWFsIGNlbGxzICsgSE1TQyBzZXVyYXQgaW50ZWdyYXRlZAojIGFjY19hbGxfY2VsbHNfbm9BY2MxID0gc3Vic2V0KGFjY19hbGxfY2VsbHMsIHN1YnNldCA9IHBhdGllbnQuaWRlbnQgIT0gIkFDQzEiKQojIGFjY19leHByID0gYWNjX2FsbF9jZWxsc19ub0FjYzFAYXNzYXlzJFJOQUBkYXRhICU+JSBhcy5kYXRhLmZyYW1lKCkKIyBobXNjX2V4cHIgID0gYWNjLmNvbWJpbmVkQGFzc2F5cyRpbnRlZ3JhdGVkQGRhdGEgJT4lIGFzLmRhdGEuZnJhbWUoKQojIGFjY19leHByID0gYWNjX2V4cHIgWyByb3duYW1lcyhobXNjX2V4cHIpLF0KIyBhbGxfZXhwciA9IGNiaW5kKGFjY19leHByLGhtc2NfZXhwcikKIyAKIyAjIGNyZWF0ZSBhbm5vdGF0aW9uIAojIGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQgID0gYXMuZGF0YS5mcmFtZShhY2NfYWxsX2NlbGxzQG1ldGEuZGF0YVssImNlbGwudHlwZSIsZHJvcCA9IEZdKQojIGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQgPSBhY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkW2NvbG5hbWVzKGFsbF9leHByKSwsZHJvcCA9IEZdCiMgYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZCA9IGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigib3JpZy5pZGVudCIpIAoKIyAjd3JpdGUgZXhwcmVzc2lvbiBhbmQgYW5ub3RhdGlvbgojIHdyaXRlLnRhYmxlKGFjY19hbm5vdGF0aW9uX2ludGVncmF0ZWQsICIuL0RhdGEvaW5mZXJDTlYvYWNjX2Fubm90YXRpb25faW50ZWdyYXRlZC50eHQiLCBhcHBlbmQgPSBGQUxTRSwgCiMgICAgICAgICAgICAgc2VwID0gIlx0IiwgZGVjID0gIi4iLHJvdy5uYW1lcyA9IEZBTFNFLCBjb2wubmFtZXMgPSBGKQojIAojIAojIHdyaXRlLnRhYmxlKGFsbF9leHByLCAiLi9EYXRhL2luZmVyQ05WL2FsbC40aWNudl9pbnRlZ3JhdGVkLnR4dCIsIGFwcGVuZCA9IEZBTFNFLCAKIyAgICAgICAgICAgICBzZXAgPSAiXHQiLCBkZWMgPSAiLiIscm93Lm5hbWVzID0gVCwgY29sLm5hbWVzID0gVCkKYGBgCgpgYGB7cn0KdHJhY2UoaW5mZXJjbnY6OnJ1bixlZGl0ID0gVCkgIyB0byBza2lwIG5vcm1hbGl6YXRpb24sIGNoYW5nZSB0byBza2lwX3Bhc3QgPSA0IChodHRwczovL2dpdGh1Yi5jb20vYnJvYWRpbnN0aXR1dGUvaW5mZXJjbnYvaXNzdWVzLzM0NikKYGBgCgpgYGB7cn0KCmluZmVyY252X29iaiA9IENyZWF0ZUluZmVyY252T2JqZWN0KHJhd19jb3VudHNfbWF0cml4PSIuL0RhdGEvaW5mZXJDTlYvYWxsLjRpY252X2ludGVncmF0ZWQudHh0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25zX2ZpbGU9Ii4vRGF0YS9pbmZlckNOVi9hY2NfYW5ub3RhdGlvbl9pbnRlZ3JhdGVkLnR4dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbGltPSJcdCIsZ2VuZV9vcmRlcl9maWxlPSIuL0RhdGEvaW5mZXJDTlYvZ2VuY29kZV92MTlfZ2VuZV9wb3MudHh0IgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAscmVmX2dyb3VwX25hbWVzPWMoIkNBRiIsICJFbmRvdGhlbGlhbCIsICJXQkMiKSkgI2dyb3VwcyBvZiBub3JtYWwgY2VsbHMKCmluZmVyY252X29ial9kZWZhdWx0ID0gaW5mZXJjbnY6OnJ1bihpbmZlcmNudl9vYmosIGN1dG9mZj0xLCBvdXRfZGlyPScuL0RhdGEvaW5mZXJDTlYvaW5mZXJjbnZfaW50ZXJncmF0ZWRfb3V0cHV0JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfYnlfZ3JvdXBzPVQsIHBsb3Rfc3RlcHM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZW5vaXNlPVRSVUUsIEhNTT1GQUxTRSwgbm9fcHJlbGltX3Bsb3Q9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBuZ19yZXM9MzAwKQp1bnRyYWNlKGluZmVyY252OjpydW4pCgoKYGBgCgoKYGBge3J9CnRyYWNlKGluZmVyY252Ojo6Z2V0X2dyb3VwX2NvbG9yX3BhbGV0dGUgLGVkaXQgPSBUKSAjIGNoYW5nZSAiU2V0MyIgdG8gIlNldDEiIGZvciBtb3JlIGRpc3Rpbmd1aXNoYWJsZSBjb2xvcnMKcGxvdF9jbnYoaW5mZXJjbnZfb2JqX2RlZmF1bHQsIG91dHB1dF9mb3JtYXQgPSAicG5nIiwgIHdyaXRlX2V4cHJfbWF0cml4ID0gRkFMU0Usb3V0X2RpciA9ICIuL0RhdGEvaW5mZXJDTlYvaW5mZXJjbnZfaW50ZXJncmF0ZWRfb3V0cHV0IixwbmdfcmVzCT04MDAsb2JzX3RpdGxlID0gIk1hbGlnbmFudCBjZWxscyIscmVmX3RpdGxlID0gIk5vcm1hbCBjZWxscyIsY29udGlnX2NleCA9IDIsIHRpdGxlID0gIkNvcHkgbnVtYmVyIHZhcmlhdGlvbiIpCnVudHJhY2UoaW5mZXJjbnY6OjpnZXRfZ3JvdXBfY29sb3JfcGFsZXR0ZSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LHJlc3VsdHM9J2FzaXMnfQpwcmludF90YWIocGx0ID0ga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi4vRGF0YS9pbmZlckNOVi9pbmZlcmNudl9pbnRlcmdyYXRlZF9vdXRwdXQvaW5mZXJjbnYucG5nIikKICAgICAgICAgICx0aXRsZSA9ICJDTlYgcGxvdCIsc3VidGl0bGVfbnVtID0gMykKYGBgCgoKYGBge3IscmVzdWx0cz0nYXNpcyd9CmxpYnJhcnkobGltbWEpCnNtb290aGVkPWFwcGx5KGluZmVyY252X29ial9kZWZhdWx0QGV4cHIuZGF0YSwyLHRyaWN1YmVNb3ZpbmdBdmVyYWdlLCBzcGFuPTAuMDEpCmNuc2lnPXNxcnQoYXBwbHkoKHNtb290aGVkLTEpXjIsMixtZWFuKSkKCmFjY19hbGxfY2VsbHMgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjX2FsbF9jZWxscywgbWV0YWRhdGEgPSBjbnNpZywgY29sLm5hbWUgPSAiY29weW51bWJlciIpCmFjY19hbGxfY2VsbHMgPSBTZXRJZGVudChvYmplY3QgPSBhY2NfYWxsX2NlbGxzLHZhbHVlID0gImNlbGwudHlwZSIpCgpwcmludF90YWIocGx0ID0gRmVhdHVyZVBsb3QoYWNjX2FsbF9jZWxscywgImNvcHludW1iZXIiLHB0LnNpemUgPSAxLGxhYmVsID0gVCxyZXBlbCA9IFQpKwogICAgICAgICAgICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG91cnM9Yygid2hpdGUiLCJsaWdodGJsdWUiLCJvcmFuZ2UiLCJyZWQiLCJkYXJrcmVkIikpCiAgICAgICAgICAsdGl0bGUgPSAiQ05WIFVNQVAiLHN1YnRpdGxlX251bSA9IDMpCgpgYGAKCgoKCiMgSE1TQyBhbmFseXNpcyAKYGBge3J9CkRlZmF1bHRBc3NheShobXNjX2NhbmNlcl9jZWxscykgPSAiaW50ZWdyYXRlZCIKYGBgCgojIyBVTUFQIAoKYGBge3J9Cmhtc2NfY2FuY2VyX2NlbGxzID0gRmluZENsdXN0ZXJzKG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLHZlcmJvc2UgPSBGLHJlc29sdXRpb24gPSAwLjUpCkRpbVBsb3Qob2JqZWN0ID0gaG1zY19jYW5jZXJfY2VsbHMscHQuc2l6ZSA9IDIpCmBgYAoKIyMgU2NvcmVzIApgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMn0KRmVhdHVyZVBsb3Qob2JqZWN0ID0gaG1zY19jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSBjKCJNWUIiLCJKQUcxIikscHQuc2l6ZSA9IDIpKwpEaW1QbG90KG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLGdyb3VwLmJ5ICA9IGMoImhwdjMzX3Bvc2l0aXZlIikscHQuc2l6ZSA9IDIpCgpgYGAKCgoKCiMjIE5NRiB7LnRhYnNldH0KYGBge3B5dGhvbn0KZnJvbSBjbm1mIGltcG9ydCBjTk1GCmltcG9ydCBwaWNrbGUKbmZlYXR1cmVzID0gIjJLIgpmID0gb3BlbignLi9EYXRhL2NOTUYvSE1TQ19jTk1GX2hhcm1vbnlfMkt2YXJnZW5lcy9jbm1mX29iai5wY2tsJywgJ3JiJykKY25tZl9vYmogPSBwaWNrbGUubG9hZChmKQpmLmNsb3NlKCkKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIi4vRGF0YS9jTk1GL0hNU0NfY05NRl9oYXJtb255XzJLdmFyZ2VuZXMvSE1TQ19jTk1GX2hhcm1vbnlfMkt2YXJnZW5lcy5rX3NlbGVjdGlvbi5wbmciKQpgYGAKCmBgYHtweXRob259CnNlbGVjdGVkX2sgPSAzCmRlbnNpdHlfdGhyZXNob2xkID0gMC4xCmNubWZfb2JqLmNvbnNlbnN1cyhrPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkLHNob3dfY2x1c3RlcmluZz1UcnVlKQp1c2FnZV9ub3JtLCBnZXBfc2NvcmVzLCBnZXBfdHBtLCB0b3BnZW5lcyA9IGNubWZfb2JqLmxvYWRfcmVzdWx0cyhLPXNlbGVjdGVkX2ssIGRlbnNpdHlfdGhyZXNob2xkPWRlbnNpdHlfdGhyZXNob2xkKQpgYGAKCmBgYHtyfQpnZXBfc2NvcmVzID0gcHkkZ2VwX3Njb3JlcwpnZXBfdHBtID0gcHkkZ2VwX3RwbQphbGxfbWV0YWdlbmVzPSBweSR1c2FnZV9ub3JtCmBgYAoKIyMgSGFybW9ueSByZXN1bHRzIHsudGFic2V0fQoKCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIHJlc3VsdHM9J2FzaXMnfQojIE1ha2UgbWV0YWdlbmUgbmFtZXMKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpW2ldID0gIm1ldGFnZW5lLiIgJT4lIHBhc3RlMChpKQp9CgojYWRkIGVhY2ggbWV0YWdlbmUgdG8gbWV0YWRhdGEKZm9yIChpIGluIDE6bmNvbChhbGxfbWV0YWdlbmVzKSkgewogIG1ldGFnZV9tZXRhZGF0YSA9IGFsbF9tZXRhZ2VuZXMgJT4lIHNlbGVjdChpKQogIGFjYzFfY2FuY2VyX2NlbGxzID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsbWV0YWRhdGEgPSBtZXRhZ2VfbWV0YWRhdGEpCn0KcHJpbnRfdGFiKHBsdCA9IAogICAgICAgICAgICBGZWF0dXJlUGxvdChvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IGNvbG5hbWVzKGFsbF9tZXRhZ2VuZXMpLGNvbWJpbmUgPSBUKSwKICAgICAgICAgIHRpdGxlID0gIm1ldGFnZW5lcyBleHByZXNzaW9uIixzdWJ0aXRsZV9udW0gPSB0b2NfdGFic19sZXZlbCkKCmBgYAoKCiMjIEVucmljaG1lbnQgYW5hbHlzaXMgYnkgdG9wIDIwMCBnZW5lcyBvZiBlYWNoIHByb2dyYW0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgcmVzdWx0cz0naGlkZSd9CgpjYW5vbmljYWxfcGF0aHdheXMgPSBtc2lnZGJyKHNwZWNpZXMgPSAiSG9tbyBzYXBpZW5zIiwgY2F0ZWdvcnkgPSAiQzIiKSAlPiUgZHBseXI6OmZpbHRlcihnc19zdWJjYXQgIT0gIkNHUCIpICU+JSAgZHBseXI6OmRpc3RpbmN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKQoKcGx0X2xpc3QgPSBsaXN0KCkKZm9yIChpIGluIDE6bmNvbChnZXBfc2NvcmVzKSkgewogIHRvcF9nZW5lcyA9IGdlcF9zY29yZXMgICU+JSAgYXJyYW5nZShkZXNjKGdlcF9zY29yZXNbaV0pKSAjc29ydCBieSBzY29yZSBhCiAgdG9wID0gaGVhZChyb3duYW1lcyh0b3BfZ2VuZXMpLDIwMCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICByZXMgPSBnZW5lc192ZWNfZW5yaWNobWVudChnZW5lcyA9IHRvcCxiYWNrZ3JvdW5kID0gcm93bmFtZXMoZ2VwX3Njb3JlcyksaG9tZXIgPSBULHRpdGxlID0gCiAgICAgICAgICAgICAgICAgICAgaSxzaWxlbnQgPSBULHJldHVybl9hbGwgPSBULGN1c3RvbV9wYXRod2F5cyA9IGNhbm9uaWNhbF9wYXRod2F5cykKICAgCiAgcGx0X2xpc3RbW2ldXSA9IHJlcyRwbHQKfQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShncm9icyA9IHBsdF9saXN0KQpgYGAKCmBgYHtyfQpmb3IgKGkgaW4gMTpuY29sKGdlcF9zY29yZXMpKSB7CiAgcmFua2VkX3ZlYyA9IGdlcF9zY29yZXMgJT4lIHB1bGwoaSkgJT4lICBzZXROYW1lcyhyb3duYW1lcyhnZXBfc2NvcmVzKSkKICBoeXBfb2JqIDwtaHlwZVJfZmdzZWEoc2lnbmF0dXJlID0gcmFua2VkX3ZlYyxnZW5lc2V0cyA9IGdlbmVzZXRzLHVwX29ubHkgPSBUKQoKICBwbHQgPSBoeXBfZG90cyhoeXBfb2JqLG1lcmdlID0gRikrIGFlcyhzaXplPWFicyhuZXMpKQogIHByaW50KHBsdCkKfQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTEwfQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQphY2MxX2NhbmNlcl9jZWxscyA9IFNldElkZW50KG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhbHVlID0gInNldXJhdF9jbHVzdGVycyIpCmZvciAoaSBpbiAxOm5jb2woZ2VwX3Njb3JlcykpIHsKICB0b3BfZ2VuZXMgPSBnZXBfc2NvcmVzICAlPiUgIGFycmFuZ2UoZGVzYyhnZXBfc2NvcmVzW2ldKSkgI3NvcnQgYnkgc2NvcmUgYQogIHRvcCA9IGhlYWQocm93bmFtZXModG9wX2dlbmVzKSw1MCkgI3Rha2UgdG9wIHRvcF9nZW5lc19udW0KICBkYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSB0b3ApJT4lIHNjYWxlKCkgJT4lIHQoKSAKICBtZXRhZ2VuZV9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjb2xuYW1lcyhhbGxfbWV0YWdlbmVzKVtpXSkKICBjb2xfbGlzdCA9IGxpc3QoY2lyY2xpemU6OmNvbG9yUmFtcDIoYygwLCAxKSwgYygid2hpdGUiLCAicmVkIikpKTsgbmFtZXMoY29sX2xpc3QpID0gY29sbmFtZXMoYWxsX21ldGFnZW5lcylbaV0KICBjb2x1bW5faGEgPSBIZWF0bWFwQW5ub3RhdGlvbihkZiA9IG1ldGFnZW5lX2RhdGEsY29sID0gY29sX2xpc3QpCiAgcHJpbnQoQ29tcGxleEhlYXRtYXA6OkhlYXRtYXAoZGF0YSxzaG93X2NvbHVtbl9uYW1lcyA9IEYscm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDcpLGNsdXN0ZXJfcm93cyA9IEYsIHRvcF9hbm5vdGF0aW9uID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5faGEsbmFtZSA9ICJaLXNjb3JlIGV4cHJlc3Npb24iKSkKICAgIAogIHBkZihwYXN0ZTAoIi4vRmlndXJlcy9OTUZfdG9wX2dlbmVzX3Byb2dyYW0iLGksIi5wZGYiKSkKICBwcmludChDb21wbGV4SGVhdG1hcDo6SGVhdG1hcChkYXRhLHNob3dfY29sdW1uX25hbWVzID0gRixyb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gNyksY2x1c3Rlcl9yb3dzID0gRiwgdG9wX2Fubm90YXRpb24gPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9oYSxuYW1lID0gIlotc2NvcmUgZXhwcmVzc2lvbiIpKQogIGRldi5vZmYoKQp9CgpgYGAKCgoKCgoKIyMgTHVtIE15byBzY29yZQoKYGBge3J9Cm9yaWdpbmFsX215b19nZW5lcyA9IGMoICJUUDYzIiwgIlRQNzMiLCAiQ0FWMSIsICJDREgzIiwgIktSVDUiLCAiS1JUMTQiLCAiQUNUQTIiLCAiVEFHTE4iLCAiTVlMSyIsICJES0szIikKb3JpZ2luYWxfbHVtX2dlbmVzID0gYygiS0lUIiwgIkVIRiIsICJFTEY1IiwgIktSVDciLCAiQ0xETjMiLCAiQ0xETjQiLCAiQ0QyNCIsICJMR0FMUzMiLCAiTENOMiIsICJTTFBJIiApCmBgYAoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTJ9CkZlYXR1cmVQbG90KGhtc2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gb3JpZ2luYWxfbXlvX2dlbmVzKQpGZWF0dXJlUGxvdChobXNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9IG9yaWdpbmFsX2x1bV9nZW5lcykKCmBgYAoKCmBgYHtyfQphY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxID0gU2V0SWRlbnQoYWNjX2NhbmNlckNlbGxzX25vQUNDMSx2YWx1ZSA9ICJwYXRpZW50LmlkZW50IikKY2FsY3VsYXRlX3Njb3JlKGRhdGFzZXQgPSBhY2NfY2FuY2VyQ2VsbHNfbm9BQ0MxLG15b19nZW5lcyA9IG9yaWdpbmFsX215b19nZW5lcyxsdW1fZ2VuZXMgPSBvcmlnaW5hbF9sdW1fZ2VuZXMpCmBgYAoKYGBge3J9CmNhbGN1bGF0ZV9zY29yZS4yIDwtIGZ1bmN0aW9uKGRhdGFzZXQsbXlvX2dlbmVzLGx1bV9nZW5lcyxsdW1fdGhyZXNob2xkID0xICwgbXlvX3RocmVzaG9sZCA9IC0xKSB7CiAgbXlvc2NvcmU9RmV0Y2hEYXRhKG9iamVjdCA9ZGF0YXNldCx2YXJzID0gIG15b19nZW5lcyxzbG90ID0gImRhdGEiKSAlPiUgcm93TWVhbnMoKQogIGxlc2NvcmU9RmV0Y2hEYXRhKG9iamVjdCA9ZGF0YXNldCx2YXJzID0gIGx1bV9nZW5lcyxzbG90ID0gImRhdGEiKSAlPiUgcm93TWVhbnMoKQogIGNvcnJlbGF0aW9uID0gY29yKGxlc2NvcmUsbXlvc2NvcmUpICU+JSByb3VuZChkaWdpdHMgPSAyKQogIG1lc3NhZ2UoImNvcnJlbGF0aW9uIG9mIGx1bSBzY29yZSBhbmQgbXlvIHNjb3JlOiIgJT4lIHBhc3RlKGNvcnJlbGF0aW9uKSkKICAKICAKICBvcmlnaW5hbF9teW9fZ2VuZXMgPSBjKCJUUDYzIiwgIlRQNzMiLCAiQ0FWMSIsICJDREgzIiwgIktSVDUiLCAiS1JUMTQiLCAiQUNUQTIiLCAiVEFHTE4iLCAiTVlMSyIsICJES0szIikKICBvcmlnaW5hbF9sdW1fZ2VuZXMgPSBjKCJLSVQiLCAiRUhGIiwgIkVMRjUiLCAiS1JUNyIsICJDTEROMyIsICJDTERONCIsICJDRDI0IiwgIkxHQUxTMyIsICJMQ04yIiwgIlNMUEkiKQogIG9yaWdfbXlvc2NvcmU9RmV0Y2hEYXRhKG9iamVjdCA9ZGF0YXNldCx2YXJzID0gIG9yaWdpbmFsX215b19nZW5lcyxzbG90ID0gImRhdGEiKSAlPiUgcm93TWVhbnMoKQogIG9yaWdfbGVzY29yZT1GZXRjaERhdGEob2JqZWN0ID1kYXRhc2V0LHZhcnMgPSAgb3JpZ2luYWxfbHVtX2dlbmVzLHNsb3QgPSAiZGF0YSIpICU+JSByb3dNZWFucygpCiAgY29ycmVsYXRpb25fdG9fb3JpZ2luYWxfbHVtID0gY29yKG9yaWdfbGVzY29yZSxsZXNjb3JlKSAlPiUgcm91bmQoZGlnaXRzID0gMikKICBjb3JyZWxhdGlvbl90b19vcmlnaW5hbF9teW8gPSBjb3Iob3JpZ19teW9zY29yZSxteW9zY29yZSkgJT4lIHJvdW5kKGRpZ2l0cyA9IDIpCgogIG1lc3NhZ2UoImNvcnJlbGF0aW9uIG9mIGx1bSBzY29yZSBhbmQgb3JpZ2luYWwgbHVtIHNjb3JlOiIgJT4lIHBhc3RlKGNvcnJlbGF0aW9uX3RvX29yaWdpbmFsX2x1bSkpCiAgbWVzc2FnZSgiY29ycmVsYXRpb24gb2YgbXlvIHNjb3JlIGFuZCBvcmlnaW5hbCBteW8gc2NvcmU6IiAlPiUgcGFzdGUoY29ycmVsYXRpb25fdG9fb3JpZ2luYWxfbXlvKSkKCiAgZGF0YXNldD1BZGRNZXRhRGF0YShkYXRhc2V0LGxlc2NvcmUtbXlvc2NvcmUsImx1bWluYWxfb3Zlcl9teW8iKQogIHByaW50KAogICAgRmVhdHVyZVBsb3Qob2JqZWN0ID0gZGF0YXNldCxmZWF0dXJlcyA9ICJsdW1pbmFsX292ZXJfbXlvIikKICApCiAgZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBkYXRhc2V0LHZhcnMgPSAibHVtaW5hbF9vdmVyX215byIpCiAgcHJpbnQoCiAgICBkYXRhICU+JSAKICAgIGdncGxvdChhZXMoIHg9bHVtaW5hbF9vdmVyX215bykpICsgCiAgICBnZW9tX2RlbnNpdHkoKSAreWxhYigiRGVuc2l0eSIpK3RoZW1lKCAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMixmYWNlPSJib2xkIikpKyB4bGFiKCJMdW1pbmFsLU15b2VwaXRoZWxpYWwgc3BlY3RydW0iKQogICAgKQogIApsdW1fY2VsbHNfbnVtID0gc3Vic2V0KHggPSBkYXRhc2V0LGx1bWluYWxfb3Zlcl9teW8gPihsdW1fdGhyZXNob2xkKSkgJT4lIG5jb2woKSAvbmNvbChkYXRhc2V0KQpteW9fY2VsbHNfbnVtID0gc3Vic2V0KHggPSBkYXRhc2V0LGx1bWluYWxfb3Zlcl9teW8gPChteW9fdGhyZXNob2xkKSkgJT4lIG5jb2woKS9uY29sKGRhdGFzZXQpCmRmID0gZGF0YS5mcmFtZShjZWxsX3R5cGUgPSBjKCJteW9fY2VsbHMiLCJsdW1fY2VsbHMiKSxwZXJjZW50YWdlID0gYyhteW9fY2VsbHNfbnVtLGx1bV9jZWxsc19udW0pKQpnZ3Bsb3QoZGF0YT1kZiwgYWVzKHg9Y2VsbF90eXBlLCB5PXBlcmNlbnRhZ2UpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIGdndGl0bGUoIkFDQyBjZWxsIHR5cGVzIikKfQoKYGBgCgoKIyMgT3JpZ2luYWwgc2NvcmUgb2YgQUNDMQoKYGBge3J9CmNhbGN1bGF0ZV9zY29yZS4yKGRhdGFzZXQgPSBhY2NfcHJpLG15b19nZW5lcyA9IG9yaWdpbmFsX215b19nZW5lcyxsdW1fZ2VuZXMgPSBvcmlnaW5hbF9sdW1fZ2VuZXMsbHVtX3RocmVzaG9sZCA9IDAsbXlvX3RocmVzaG9sZCA9IDApCmBgYApgYGB7cn0KY2FsY3VsYXRlX3Njb3JlKGRhdGFzZXQgPSBobXNjX2NhbmNlcl9jZWxscyxteW9fZ2VuZXMgPSBvcmlnaW5hbF9teW9fZ2VuZXMsbHVtX2dlbmVzID0gb3JpZ2luYWxfbHVtX2dlbmVzLGx1bV90aHJlc2hvbGQgPSAwLG15b190aHJlc2hvbGQgPSAwKQpgYGAKCgpgYGB7cn0KZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBobXNjX2NhbmNlcl9jZWxscyx2YXJzID0gYyhvcmlnaW5hbF9sdW1fZ2VuZXMpKQphID0gY29yKGRhdGEpCkNvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKG1hdHJpeCA9IGNvcihkYXRhKSxuYW1lID0gInBlYXJzb24iKQpgYGAKCgojIyBIUFYKIyMjIEhQViBVTUFQCgpgYGB7cn0KSFBWMzNfUDMgPSBmcmVhZCgiLi9EYXRhL0hQVjMzX1AzLnR4dCIsY29sLm5hbWVzID0gYygicGxhdGUiLCJyZWFkcyIpKSAlPiUgYXMuZGF0YS5mcmFtZSgpCkhQVjMzX1AzLmRmID0gSFBWMzNfUDMgJT4lIG11dGF0ZSgKICBwbGF0ZSA9IGdzdWIoeCA9SFBWMzNfUDMkcGxhdGUsIHJlcGxhY2VtZW50ID0gIiIscGF0dGVybiA9ICJfLiokIikgCiAgJT4lIGdzdWIocGF0dGVybiA9ICItUCIscmVwbGFjZW1lbnQgPSAiLlAiKSAKICAlPiUgZ3N1YihwYXR0ZXJuID0gIi0iLHJlcGxhY2VtZW50ID0gIl8iLCkKICApCkhQVjMzX1AzLmRmID0gSFBWMzNfUDMuZGYgJT4lIGRwbHlyOjpmaWx0ZXIoSFBWMzNfUDMuZGYkcGxhdGUgJWluJSBjb2xuYW1lcyhobXNjX2NhbmNlcl9jZWxscykpCnJvd25hbWVzKEhQVjMzX1AzLmRmKSAgPC0gSFBWMzNfUDMuZGYkcGxhdGUKSFBWMzNfUDMuZGYkcGxhdGUgPSBOVUxMCgoKSFBWMzNfUDIgPSBmcmVhZCgiLi9EYXRhL0hQVjMzX1AyLnR4dCIsY29sLm5hbWVzID0gYygicGxhdGUiLCJyZWFkcyIpKSAlPiUgYXMuZGF0YS5mcmFtZSgpCkhQVjMzX1AyLmRmID0gSFBWMzNfUDIgJT4lIG11dGF0ZSgKICBwbGF0ZSA9IGdzdWIoeCA9SFBWMzNfUDIkcGxhdGUsIHJlcGxhY2VtZW50ID0gIiIscGF0dGVybiA9ICJfLiokIikgCiAgJT4lIGdzdWIocGF0dGVybiA9ICJwbGF0ZTItIixyZXBsYWNlbWVudCA9ICJwbGF0ZTJfIiwpCiAgJT4lIGdzdWIocGF0dGVybiA9ICItIixyZXBsYWNlbWVudCA9ICJcXC4iLCkKICApCkhQVjMzX1AyLmRmID0gSFBWMzNfUDIuZGYgJT4lIGRwbHlyOjpmaWx0ZXIoSFBWMzNfUDIuZGYkcGxhdGUgJWluJSBjb2xuYW1lcyhobXNjX2NhbmNlcl9jZWxscykpCnJvd25hbWVzKEhQVjMzX1AyLmRmKSAgPC0gSFBWMzNfUDIuZGYkcGxhdGUKSFBWMzNfUDIuZGYkcGxhdGUgPSBOVUxMCgpIUFYzMyA9IHJiaW5kKEhQVjMzX1AzLmRmLEhQVjMzX1AyLmRmKQpobXNjX2NhbmNlcl9jZWxscyA9IEFkZE1ldGFEYXRhKG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLG1ldGFkYXRhID0gSFBWMzMsY29sLm5hbWUgPSAiSFBWMzMucmVhZHMiKQpGZWF0dXJlUGxvdChobXNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJIUFYzMy5yZWFkcyIsbWF4LmN1dG9mZiA9IDEwKQpgYGAKCgpgYGB7cn0KCmRhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gaG1zY19jYW5jZXJfY2VsbHMsdmFycyA9ICJIUFYzMy5yZWFkcyIpCgpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIwIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWMzMucmVhZHMgPT0gMCx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIxIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWMzMucmVhZHMgPT0gMSx0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIyIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWMzMucmVhZHMgPT0gMix0cnVlID0gMSxmYWxzZSA9IDApKQpkYXRhID0gZGF0YSAlPiUgbXV0YXRlKCIzLTIzIHJlYWRzIiA9IGlmX2Vsc2UoY29uZGl0aW9uID0gSFBWMzMucmVhZHMgPj0zICZIUFYzMy5yZWFkcyAgPDI0LHRydWUgPSAxLGZhbHNlID0gMCkpCmRhdGEgPSBkYXRhICU+JSBtdXRhdGUoIjI0KyByZWFkcyIgPSBpZl9lbHNlKGNvbmRpdGlvbiA9IEhQVjMzLnJlYWRzID49MjQsdHJ1ZSA9IDEsZmFsc2UgPSAwKSkKZGF0YSA9IGNvbFN1bXMoZGF0YVssMjpuY29sKGRhdGEpXSkgJT4lIGFzLmRhdGEuZnJhbWUoKQpuYW1lcyhkYXRhKVsxXSA9ICJjb3VudCIKZGF0YSA9IHJvd25hbWVzX3RvX2NvbHVtbihkYXRhLHZhciA9ICJiaW4iKQpkYXRhCmdncGxvdChkYXRhPWRhdGEsIGFlcyh4PWZhY3RvcihiaW4sbGV2ZWxzID0gYygiMCByZWFkcyIsIjEgcmVhZHMiLCIyIHJlYWRzIiwiMy0yMyByZWFkcyIsIjI0KyByZWFkcyIpKSwgeT1jb3VudCkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9InN0ZWVsYmx1ZSIpICsgeGxhYigiSFBWIFJlYWRzIikrIHRoZW1lX21pbmltYWwoKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50KSwgdmp1c3Q9LTAuNSwgY29sb3I9ImJsYWNrIiwgc2l6ZT0zLjUpCmBgYAoKCmBgYHtyfQpocHYzM19wb3NpdGl2ZSA9IEhQVjMzICU+JSBkcGx5cjo6bXV0YXRlKGhwdjMzX3Bvc2l0aXZlID0gY2FzZV93aGVuKHJlYWRzID49IDEwIH4gInBvc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkcyA8IDEwIH4gIm5lZ2F0aXZlIikKKQoKCgpocHYzM19wb3NpdGl2ZSRyZWFkcyA9IE5VTEwKaG1zY19jYW5jZXJfY2VsbHMgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBobXNjX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IGhwdjMzX3Bvc2l0aXZlKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQpEaW1QbG90KG9iamVjdCA9IGhtc2NfY2FuY2VyX2NlbGxzLGdyb3VwLmJ5ICA9IGMoImhwdjMzX3Bvc2l0aXZlIikscHQuc2l6ZSA9IDIpKwpGZWF0dXJlUGxvdChvYmplY3QgPSBobXNjX2NhbmNlcl9jZWxscyxmZWF0dXJlcyA9ICJNWUIiLHB0LnNpemUgPSAyKQoKYGBgCgoKYGBge3J9CmxpYnJhcnkoYmlvbWFSdCkKZW5zZW1ibCA9IHVzZUVuc2VtYmwoYmlvbWFydD0iZW5zZW1ibCIsIGRhdGFzZXQ9ImhzYXBpZW5zX2dlbmVfZW5zZW1ibCIpCmBgYAoKCgojIyMgREVHIExSIGxhdGVudCB2YXJzIHBsYXRlCmBgYHtyfQpEZWZhdWx0QXNzYXkoaG1zY19jYW5jZXJfY2VsbHMpID0gImludGVncmF0ZWQiCmhtc2NfY2FuY2VyX2NlbGxzID0gU2V0SWRlbnQoaG1zY19jYW5jZXJfY2VsbHMsdmFsdWUgPSAiaHB2MzNfcG9zaXRpdmUiKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KCJiaW9tYVJ0IikKCmZlYXR1cmVzID0gVmFyaWFibGVGZWF0dXJlcyhobXNjX2NhbmNlcl9jZWxscykKZmVhdHVyZXMgPSBobXNjX2NhbmNlcl9jZWxsc0Bhc3NheXMkUk5BQGRhdGEgJT4lIHJvd01lYW5zKCkgJT4lIHNvcnQoZGVjcmVhc2luZyA9IFQpICU+JSBoZWFkKDMwMDApICU+JSBuYW1lcygpCgphY2NfZGVnIDwtCiAgRmluZE1hcmtlcnMoCiAgICBobXNjX2NhbmNlcl9jZWxscywKICAgIGlkZW50LjEgPSAicG9zaXRpdmUiLAogICAgaWRlbnQuMiA9ICJuZWdhdGl2ZSIsCiAgICBmZWF0dXJlcyA9IGZlYXR1cmVzLAogICAgZGVuc2lmeSA9IFQsCiAgICBhc3NheSA9ICJSTkEiLAogICAgdGVzdC51c2UgPSAiTFIiLAogICAgbGF0ZW50LnZhcnMgPSAicGxhdGUiLAogICAgbG9nZmMudGhyZXNob2xkID0gMC4xLAogICAgbWluLnBjdCA9IDAuMSwKICAgIG9ubHkucG9zID0gRiwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4obG9nKHJvd01lYW5zKHgpICsgMSwgYmFzZSA9IDIpKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgICAjIHJldHVybihsb2cocm93TWVhbnMoZXhwbTEoeCkpICsgMSwgYmFzZSA9IDIpKQoKICAgIH0KICApCmFjY19kZWckZmRyPC1wLmFkanVzdChwID0gYXMudmVjdG9yKGFjY19kZWckcF92YWwpICxtZXRob2QgPSAiZmRyIiApCgpgYGAKCgpgYGB7cn0KcmFua2VkX3ZlYyA9IGFjY19kZWdbLCJhdmdfbG9nMkZDIl0lPiUgc2V0TmFtZXMocm93bmFtZXMoYWNjX2RlZykpICU+JSBuYS5vbWl0KCkgIyBtYWtlIG5hbWVkIHZlY3RvcgoKaHlwX29iaiA8LWh5cGVSX2Znc2VhKHNpZ25hdHVyZSA9IHJhbmtlZF92ZWMsZ2VuZXNldHMgPSBnZW5lc2V0cyx1cF9vbmx5ID0gRikKaHlwX2RvdHMoaHlwX29iaixtZXJnZSA9IEYp15YKCgpgYGAKCmBgYHtyfQphY2NfZGVnCmFjY19kZWdbYygiTVlCIiwiSkFHMSIpLF0KCmBgYAoKCgp2b2xjYW5vIHBsb3QgbG9nMihtZWFuIGxvZ1RQTSBIUFYrKSAtIGxvZzIobWVhbiBsb2dUUE0gSFBWLSkKYGBge3J9CnZvbGNhbm9fcGxvdChkZV9nZW5lcyA9IGFjY19kZWcsZmNfY3V0b2ZmID0gMS4zLCBmZHJfY3V0b2ZmID0gMC4xLHNob3dfZ2VuZV9uYW1lcyA9IGMoIk1ZQiIsIkpBRzEiKSxpZGVudDEgPSAiSFBWMzMgcG9zaXRpdmUiLGlkZW50MiA9ICJIUFYzMyBuZWdhdGl2ZSIsdG9wX2dlbmVzX3RleHQgPSA1KQoKYWNjX2RlZzIgPSBhY2NfZGVnICU+JSBtdXRhdGUoYXZnX2xvZzJGQyA9IGV4cChhdmdfbG9nMkZDKSkKdm9sY2Fub19wbG90KGRlX2dlbmVzID0gYWNjX2RlZzIsZmNfY3V0b2ZmID0gMioqKDEuMyksIGZkcl9jdXRvZmYgPSAwLjEsc2hvd19nZW5lX25hbWVzID0gYygiTVlCIiwiSkFHMSIpLGlkZW50MSA9ICJIUFYzMyBwb3NpdGl2ZSIsaWRlbnQyID0gIkhQVjMzIG5lZ2F0aXZlIix0b3BfZ2VuZXNfdGV4dCA9IDUpCmBgYAoKdm9sY2FubyBwbG90IGxvZzIobWVhbiBsb2dUUE0gSFBWKykgLSBsb2cyKG1lYW4gbG9nVFBNIEhQVi0pCgpgYGB7cn0KCmFjY19kZWcgPC0KICBGaW5kTWFya2VycygKICAgIGFjYzFfY2FuY2VyX2NlbGxzLAogICAgaWRlbnQuMSA9ICJwb3NpdGl2ZSIsCiAgICBpZGVudC4yID0gIm5lZ2F0aXZlIiwKICAgIGZlYXR1cmVzID0gZmVhdHVyZXMsCiAgICBkZW5zaWZ5ID0gVCwKICAgIGFzc2F5ID0gIlJOQSIsCiAgICB0ZXN0LnVzZSA9ICJMUiIsCiAgICBsYXRlbnQudmFycyA9ICJwbGF0ZSIsCiAgICBsb2dmYy50aHJlc2hvbGQgPSAwLjM1LAogICAgbWluLnBjdCA9IDAuMSwKICAgIG1lYW4uZnhuID0gZnVuY3Rpb24oeCkgewogICAgICByZXR1cm4ocm93TWVhbnMoeCkgKyAxKSAjIGNoYW5nZSBmdW5jIHRvIGNhbGN1bGF0ZSBsb2dGQyBpbiBsb2cgc3BhY2UgZGF0YSAoZGVmYXVsdCB0byBleHBvbmVudCBkYXRhKQogICAgfQogICkKYWNjX2RlZyRmZHI8LXAuYWRqdXN0KHAgPSBhcy52ZWN0b3IoYWNjX2RlZyRwX3ZhbCkgLG1ldGhvZCA9ICJmZHIiICkKYGBgCgpgYGB7cn0KYWNjX2RlZ1tjKCJNWUIiLCJKQUcxIiksXQpgYGAKCgp2b2xjYW5vIHBsb3QgKG1lYW4gbG9nVFBNIEhQVispIC0gKG1lYW4gbG9nVFBNIEhQVi0pCgpgYGB7cn0Kdm9sY2Fub19wbG90KGRlX2dlbmVzID0gYWNjX2RlZyxmY19jdXRvZmYgPSAxLjMsIGZkcl9jdXRvZmYgPSAwLjEsc2hvd19nZW5lX25hbWVzID0gYygiTVlCIiwiSkFHMSIpLGlkZW50MSA9ICJIUFYzMyBwb3NpdGl2ZSIsaWRlbnQyID0gIkhQVjMzIG5lZ2F0aXZlIix0b3BfZ2VuZXNfdGV4dCA9IDUpK3hsYWIoImF2ZyBkaWZmIikKYGBgCgojIyMgSFBWIHZzIGdlbmVzCmBgYHtyIGZpZy53aWR0aD04fQpnZW5lcyA9IGMoIkFLNCIsICJBTkxOIiwgIkNBUEciLCAiSUZUMTIyIiwgIkpBRzEiLCAiTVlCIiwgIlBCUk0xIiApCm15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIixnZW5lcykpCmRmID0gcmVzaGFwZTI6Om1lbHQobXliX3ZzX2hwdix2YWx1ZS5uYW1lID0gImxvZ1RQTSIpICU+JSBkcGx5cjo6cmVuYW1lKGdlbmUgPSB2YXJpYWJsZSkKCgpzdGF0LnRlc3QgPC0gZGYgJT4lCiAgICBncm91cF9ieShnZW5lKSAlPiUKICB3aWxjb3hfdGVzdChsb2dUUE0gfiBocHYzM19wb3NpdGl2ZSkgJT4lCiAgbXV0YXRlKHkucG9zaXRpb24gPSA1KQoKc3RhdC50ZXN0CgpzdGF0LnRlc3QgPC0gc3RhdC50ZXN0ICU+JSAKICBhZGRfeHlfcG9zaXRpb24oeCA9ICJnZW5lIiwgZG9kZ2UgPSAwLjgpCgpnZ2JveHBsb3QoCiAgZGYsCiAgeCA9ICJnZW5lIiwKICB5ID0gImxvZ1RQTSIsCiAgY29sb3IgPSAiaHB2MzNfcG9zaXRpdmUiLAogIHBhbGV0dGUgPSAiamNvIiwKICBhZGQgPSAiaml0dGVyIgopKyBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LHkucG9zaXRpb24gPSAxMywgbGFiZWwgPSAicCA9IHtwfSIscmVtb3ZlLmJyYWNrZXQgPSBUKQpgYGAKCmBgYHtyfQpub3RjaF9nZW5lcyA9IGMoIkpBRzEiLCJKQUcyIiwiTk9UQ0gzIiwiTk9UQ0gyIiwiTk9UQ0gxIiwiRExMMSIsIk1ZQiIsIkhFUzQiLCJIRVkxIiwiSEVZMiIsIk5SQVJQIikKZm9yIChnZW5lICBpbiBub3RjaF9nZW5lcykgewogIG15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIixnZW5lKSkgCiAgbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2ZSA9IHBhc3RlKCJIUFYzMyIsbXliX3ZzX2hwdiRocHYzM19wb3NpdGl2KQoKICBwID0gZ2dib3hwbG90KG15Yl92c19ocHYsIHggPSAiaHB2MzNfcG9zaXRpdmUiLCB5ID0gZ2VuZSwKICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLAogICAgICAgICAgICBhZGQgPSAiaml0dGVyIikrIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLGNvbXBhcmlzb25zID0gbGlzdChjKCJIUFYzMyBwb3NpdGl2ZSIsIkhQVjMzIG5lZ2F0aXZlIikpKSsgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gZnVuY3Rpb24oeCkgZGF0YS5mcmFtZSh5PW1heCh4KSoxLjIsIGxhYmVsID0gcGFzdGUoIk1lYW49Iixyb3VuZChtZWFuKHgpLGRpZ2l0cyA9IDIpKSksIGdlb209InRleHQiKSAreWxhYigibG9nMihnZW5lKSIpK2dndGl0bGUoZ2VuZSkKICBwcmludF90YWIocCx0aXRsZSA9IGdlbmUpCn0KCmBgYAoKCmBgYHtyfQpub3RjaF90YXJnZXRzID0gYygiTk9UQ0gzIiwiSEVTNCIsIkhFWTEiLCJIRVkyIiwiTlJBUlAiKSAKbm90Y2hfbGlnYW5kID0gYygiSkFHMSIsIkpBRzIiLCJETEwxIikKbm90Y2hfZ2VuZXMgPSBsaXN0KG5vdGNoX3RhcmdldHMgPSBub3RjaF90YXJnZXRzLG5vdGNoX2xpZ2FuZCA9IG5vdGNoX2xpZ2FuZCkKZm9yIChpICBpbiAxOmxlbmd0aChub3RjaF9nZW5lcykpIHsKICBnZW5lcyA9IG5vdGNoX2dlbmVzW1tpXV0KICBuYW1lID0gbmFtZXMoIG5vdGNoX2dlbmVzKVtpXQogIG15Yl92c19ocHYgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoZ2VuZXMpKSAlPiUgcm93TWVhbnMoKQogIG15Yl92c19ocHYgPSBteWJfdnNfaHB2ICU+JSBjYmluZChGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoImhwdjMzX3Bvc2l0aXZlIikpKQogIGNvbG5hbWVzKG15Yl92c19ocHYpWzFdID0gImdlbmVfc2V0IgogIG15Yl92c19ocHYkaHB2MzNfcG9zaXRpdmUgPSBwYXN0ZSgiSFBWMzMiLG15Yl92c19ocHYkaHB2MzNfcG9zaXRpdikKCiAgcCA9IGdnYm94cGxvdChteWJfdnNfaHB2LCB4ID0gImhwdjMzX3Bvc2l0aXZlIiwgeSA9ICJnZW5lX3NldCIsCiAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwKICAgICAgICAgICAgYWRkID0gImppdHRlciIpKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0Iixjb21wYXJpc29ucyA9IGxpc3QoYygiSFBWMzMgcG9zaXRpdmUiLCJIUFYzMyBuZWdhdGl2ZSIpKSkrIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IGZ1bmN0aW9uKHgpIGRhdGEuZnJhbWUoeT1tYXgoeCkqMS4yLCBsYWJlbCA9IHBhc3RlKCJNZWFuPSIscm91bmQobWVhbih4KSxkaWdpdHMgPSAyKSkpLCBnZW9tPSJ0ZXh0IikgK3lsYWIoImxvZzIoZ2VuZSkiKStnZ3RpdGxlKG5hbWUpCiBwcmludChwKQp9CgpgYGAKCmBgYHtyfQogIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJNWUIiLCJteW9fc2NvcmUiKSkKZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1NWUIsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCgoKICBjb3JfZGF0YSA9IEZldGNoRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyx2YXJzID0gYygiSkFHMSIsIm15b19zY29yZSIpKQpnZ3Bsb3QoY29yX2RhdGEsIGFlcyh4PUpBRzEsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCgogIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJKQUcyIiwibXlvX3Njb3JlIikpCmdncGxvdChjb3JfZGF0YSwgYWVzKHg9SkFHMiwgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKCiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IGMoIkRMTDEiLCJteW9fc2NvcmUiKSkKZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1ETEwxLCB5PW15b19zY29yZSkpICsgCiAgICBzdGF0X2NvcihtZXRob2QgPSAicGVhcnNvbiIpKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSAgKwogIGdlb21fcG9pbnQoKQoKCiAgY29yX2RhdGEgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG5vdGNoX3RhcmdldHMpICU+JSByb3dNZWFucygpCiAgY29yX2RhdGEgPSBjb3JfZGF0YSAlPiUgY2JpbmQoRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJteW9fc2NvcmUiKSkpCiAgY29sbmFtZXMoY29yX2RhdGEpWzFdID0gIm5vdGNoX3RhcmdldHMiCgogIGdncGxvdChjb3JfZGF0YSwgYWVzKHg9bm90Y2hfdGFyZ2V0cywgeT1teW9fc2NvcmUpKSArIAogICAgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKSsKICAgIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgICsKICBnZW9tX3BvaW50KCkKICAKICAKICAgIGNvcl9kYXRhID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBub3RjaF9saWdhbmQpICU+JSByb3dNZWFucygpCiAgY29yX2RhdGEgPSBjb3JfZGF0YSAlPiUgY2JpbmQoRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBjKCJteW9fc2NvcmUiKSkpCiAgY29sbmFtZXMoY29yX2RhdGEpWzFdID0gIm5vdGNoX2xpZ2FuZCIKCiAgZ2dwbG90KGNvcl9kYXRhLCBhZXMoeD1ub3RjaF9saWdhbmQsIHk9bXlvX3Njb3JlKSkgKyAKICAgIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIikrCiAgICBnZW9tX3Ntb290aChtZXRob2Q9bG0pICArCiAgZ2VvbV9wb2ludCgpCiAgCmBgYAoKCmBgYHtyfQpub3RjaF9zY29yZSA9IEZldGNoRGF0YShvYmplY3QgPSBhbGxfYWNjX2NhbmNlcl9jZWxscyx2YXJzID0gbm90Y2hfdGFyZ2V0cykgJT4lIHJvd01lYW5zKCkKYWxsX2FjY19jYW5jZXJfY2VsbHMgID0gQWRkTWV0YURhdGEob2JqZWN0ID0gYWxsX2FjY19jYW5jZXJfY2VsbHMsbWV0YWRhdGEgPSBub3RjaF9zY29yZSxjb2wubmFtZSA9ICJub3RjaF9zY29yZSIpCkZlYXR1cmVQbG90KG9iamVjdCA9IGFsbF9hY2NfY2FuY2VyX2NlbGxzLGZlYXR1cmVzID0gIm5vdGNoX3Njb3JlIiApCmBgYAoKCmBgYHtyfQpteW9fbWFya2VycyA9IGMoIlRQNjMiLCAiVFA3MyIsICJLUlQxNCIsICJDREgzIikKc2NvcmUgPSBGZXRjaERhdGEob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsdmFycyA9IG15b19tYXJrZXJzKSAlPiUgcm93TWVhbnMoKQphY2MxX2NhbmNlcl9jZWxscyAgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IHNjb3JlLGNvbC5uYW1lID0gIm15b19tYXJrZXJzX3Njb3JlIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAibXlvX21hcmtlcnNfc2NvcmUiLHB0LnNpemUgPSAyICkKCgptYXJrZXJzID0gYygiQ0xETjMiLCAiQU5YQTgiLCAiRUhGIiwgIktJVCIpCnNjb3JlID0gRmV0Y2hEYXRhKG9iamVjdCA9IGFjYzFfY2FuY2VyX2NlbGxzLHZhcnMgPSBtYXJrZXJzKSAlPiUgcm93TWVhbnMoKQphY2MxX2NhbmNlcl9jZWxscyAgPSBBZGRNZXRhRGF0YShvYmplY3QgPSBhY2MxX2NhbmNlcl9jZWxscyxtZXRhZGF0YSA9IHNjb3JlLGNvbC5uYW1lID0gImx1bV9tYXJrZXJzX3Njb3JlIikKRmVhdHVyZVBsb3Qob2JqZWN0ID0gYWNjMV9jYW5jZXJfY2VsbHMsZmVhdHVyZXMgPSAibHVtX21hcmtlcnNfc2NvcmUiICxwdC5zaXplID0gMiApCmBgYAoKCjxzY3JpcHQgc3JjPSJodHRwczovL2h5cG90aGVzLmlzL2VtYmVkLmpzIiBhc3luYz48L3NjcmlwdD4K